From 5abfdf4eb03694aaeed6e731eb9ce12f25471e2b Mon Sep 17 00:00:00 2001 From: David Sansome Date: Wed, 28 Dec 2011 14:13:12 +0100 Subject: [PATCH 01/40] Fix a cmake error when getting the git revision number of an exact tag checkout (cherry picked from commit 9e2e035ae1a25bc5f37a17ae7ea10ba7c37fb328) --- cmake/Version.cmake | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cmake/Version.cmake b/cmake/Version.cmake index cb22eb7fa..a64bfc1ad 100644 --- a/cmake/Version.cmake +++ b/cmake/Version.cmake @@ -139,10 +139,13 @@ else(FORCE_GIT_REVISION) message(FATAL_ERROR "Failed to parse git revision string '${GIT_REV}'") endif(NOT GIT_PARTS) - list(GET GIT_PARTS 0 GIT_TAGNAME) - list(GET GIT_PARTS 1 GIT_COMMITCOUNT) - list(GET GIT_PARTS 2 GIT_SHA1) - set(HAS_GET_REVISION ON) + list(LENGTH GIT_PARTS GIT_PARTS_LENGTH) + if(GIT_PARTS_LENGTH EQUAL 3) + list(GET GIT_PARTS 0 GIT_TAGNAME) + list(GET GIT_PARTS 1 GIT_COMMITCOUNT) + list(GET GIT_PARTS 2 GIT_SHA1) + set(HAS_GET_REVISION ON) + endif(GIT_PARTS_LENGTH EQUAL 3) endif(${GIT_INFO_RESULT} EQUAL 0) endif(NOT GIT_EXECUTABLE-NOTFOUND) endif(FORCE_GIT_REVISION) From cf2c3a981544cb032e2ed9636e53f5653fd1103d Mon Sep 17 00:00:00 2001 From: David Sansome Date: Wed, 28 Dec 2011 14:24:10 +0100 Subject: [PATCH 02/40] Update the script that uploads stable builds to the PPA to work with git (cherry picked from commit 5b9a273227648919c8c57c73df9c980c049eccc4) --- dist/uploadtoppa.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/dist/uploadtoppa.sh b/dist/uploadtoppa.sh index 4eb446a6b..c4d29a323 100755 --- a/dist/uploadtoppa.sh +++ b/dist/uploadtoppa.sh @@ -1,16 +1,16 @@ #!/bin/sh -e -BRANCH=$1 +REFSPEC=$1 DIST=$2 -if [ -z "$BRANCH" -o -z "$DIST" ]; then - echo "Usage: $0 " +if [ -z "$REFSPEC" -o -z "$DIST" ]; then + echo "Usage: $0 " echo "Example: $0 tags/0.7 natty" exit 1 fi PPA=ppa:me-davidsansome/clementine -REPO=http://svn.clementine-player.org/clementine-mirror/$1 +REPO=https://code.google.com/p/clementine-player/ BASE=`pwd` DIRECTORY=clementine @@ -19,9 +19,13 @@ DIRECTORY=clementine rm -rfv $BASE/$DIRECTORY $BASE/*.diff.gz $BASE/*.tar.gz $BASE/*.dsc $BASE/*_source.changes # Checkout -svn checkout $REPO $DIRECTORY +git init $DIRECTORY +cd $BASE/$DIRECTORY +git fetch -t $REPO $REFSPEC +git checkout $REFSPEC # Generate changelog and maketarball.sh +mkdir $BASE/$DIRECTORY/bin cd $BASE/$DIRECTORY/bin cmake .. -DDEB_DIST=$DIST -DWITH_DEBIAN=ON rm -rfv $BASE/$DIRECTORY/bin/* @@ -31,7 +35,7 @@ cd $BASE/$DIRECTORY/dist ./maketarball.sh mv -v $BASE/$DIRECTORY/dist/*.orig.tar.gz $BASE/ rm -v $BASE/$DIRECTORY/dist/*.tar.gz -find $BASE/$DIRECTORY/ -depth -path '*/.svn*' -delete +rm -vrf $BASE/$DIRECTORY/.git # Build the deb cd $BASE/$DIRECTORY From 80aecb2eec220c7fc7206e2cd82781caa4cb2244 Mon Sep 17 00:00:00 2001 From: Arnaud Bienner Date: Wed, 28 Dec 2011 20:04:12 +0100 Subject: [PATCH 03/40] Update 'All the translators' URL with Transifex (cherry picked from commit 401c72bf7d5c81b7bd0b0d588b0320aed0884307) --- src/ui/about.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/about.cpp b/src/ui/about.cpp index 5085c131e..4b42963ce 100644 --- a/src/ui/about.cpp +++ b/src/ui/about.cpp @@ -70,8 +70,8 @@ QString About::MakeHtml() const { foreach (const Person& person, thanks_to_) ret += "
" + MakeHtml(person); - ret += QString("
" + tr("All the translators") + " <" - "https://translations.launchpad.net/clementine>"); + ret += QString("
" + tr("All the translators") + " <" + "https://www.transifex.net/projects/p/clementine>"); ret += QString("
%1

").arg(tr("...and all the Amarok contributors")); ret += QString("

%1").arg(tr("And:")); From 36b92b229f2b3f77238aab1380a7f5a00308c121 Mon Sep 17 00:00:00 2001 From: David Sansome Date: Tue, 3 Jan 2012 11:53:34 +0000 Subject: [PATCH 04/40] Always use the C locale when getting the date to put in the debian changelog - dpkg-buildpackage complains otherwise (cherry picked from commit 44db77da487a0eb4315ef6f7e63a2d795b0aa3de) --- debian/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/CMakeLists.txt b/debian/CMakeLists.txt index 456a70899..2a8693f74 100644 --- a/debian/CMakeLists.txt +++ b/debian/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.8) -execute_process(COMMAND date "+%a, %-d %b %Y %H:%M:%S %z" +execute_process(COMMAND env LC_ALL=C date "+%a, %-d %b %Y %H:%M:%S %z" OUTPUT_VARIABLE DEB_DATE OUTPUT_STRIP_TRAILING_WHITESPACE) set(DEB_REWRITE_RULES ON CACHE BOOL "Rewrite the debian rules file from rules.in") From ac44b33ec8da247aa2ec12a6726a3c31d9cf3a7b Mon Sep 17 00:00:00 2001 From: David Sansome Date: Wed, 4 Jan 2012 22:10:41 +0000 Subject: [PATCH 05/40] Don't set a "file" url scheme on files in devices that already have URL prefixes (like afc:// for iPod Touches) Fixes issue 2564 (cherry picked from commit 4cbc221f0001427c85a08ef30ca01c147a462aae) --- src/core/song.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/song.cpp b/src/core/song.cpp index 9af1e0c4b..b8b12aada 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -849,7 +849,12 @@ void Song::InitFromLastFM(const lastfm::Track& track) { QString filename = QString::fromLocal8Bit(track->ipod_path); filename.replace(':', '/'); - d->url_ = QUrl::fromLocalFile(prefix + filename); + if (prefix.contains("://")) { + d->url_ = prefix + filename; + } else { + d->url_ = QUrl::fromLocalFile(prefix + filename); + } + d->basefilename_ = QFileInfo(filename).fileName(); } From f1af27f84977269cc041c01d11fa68a407c7f166 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Wed, 4 Jan 2012 14:08:31 +0000 Subject: [PATCH 06/40] Move mac init code after logging init. (cherry picked from commit 058e421827fbc801f5745429f58d7d2bf4375672) --- src/main.cpp | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 78c77851f..527ec0264 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -142,6 +142,27 @@ void LoadTranslation(const QString& prefix, const QString& path, #include #endif +void IncreaseFDLimit() { +#ifdef Q_OS_DARWIN + // Bump the soft limit for the number of file descriptors from the default of 256 to + // the maximum (usually 10240). + struct rlimit limit; + getrlimit(RLIMIT_NOFILE, &limit); + + // getrlimit() lies about the hard limit so we have to check sysctl. + int max_fd = 0; + size_t len = sizeof(max_fd); + sysctlbyname("kern.maxfilesperproc", &max_fd, &len, NULL, 0); + + limit.rlim_cur = max_fd; + int ret = setrlimit(RLIMIT_NOFILE, &limit); + + if (ret == 0) { + qLog(Debug) << "Max fd:" << max_fd; + } +#endif +} + int main(int argc, char *argv[]) { if (CrashReporting::SendCrashReport(argc, argv)) { return 0; @@ -153,25 +174,6 @@ int main(int argc, char *argv[]) { // Do Mac specific startup to get media keys working. // This must go before QApplication initialisation. mac::MacMain(); - - { - // Bump the soft limit for the number of file descriptors from the default of 256 to - // the maximum (usually 10240). - struct rlimit limit; - getrlimit(RLIMIT_NOFILE, &limit); - - // getrlimit() lies about the hard limit so we have to check sysctl. - int max_fd = 0; - size_t len = sizeof(max_fd); - sysctlbyname("kern.maxfilesperproc", &max_fd, &len, NULL, 0); - - limit.rlim_cur = max_fd; - int ret = setrlimit(RLIMIT_NOFILE, &limit); - - if (ret == 0) { - qLog(Debug) << "Max fd:" << max_fd; - } - } #endif QCoreApplication::setApplicationName("Clementine"); @@ -289,6 +291,8 @@ int main(int argc, char *argv[]) { logging::SetLevels(options.log_levels()); g_log_set_default_handler(reinterpret_cast(&logging::GLog), NULL); + IncreaseFDLimit(); + QtSingleApplication a(argc, argv); #ifdef Q_OS_DARWIN QCoreApplication::setLibraryPaths( From 4a13d0ce29573a004f4b65ce626a3a3bf3e6ea1c Mon Sep 17 00:00:00 2001 From: John Maguire Date: Wed, 4 Jan 2012 15:24:53 +0000 Subject: [PATCH 07/40] Add filesystem watcher using Mac FSEvents API. (cherry picked from commit 96aa95bebd30ba550b0cec7ce7e88afa8fc19ca3) --- src/CMakeLists.txt | 2 ++ src/core/macfslistener.h | 38 ++++++++++++++++++++ src/core/macfslistener.mm | 75 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 src/core/macfslistener.h create mode 100644 src/core/macfslistener.mm diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 23fb96c16..443e70be6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -711,6 +711,7 @@ optional_source(APPLE ${GROWL}/Headers ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/google-breakpad/client/mac/build/Release/Breakpad.framework SOURCES + core/macfslistener.mm core/macglobalshortcutbackend.mm core/mac_startup.mm devices/macdevicelister.mm @@ -720,6 +721,7 @@ optional_source(APPLE widgets/maclineedit.mm widgets/osd_mac.mm HEADERS + core/macfslistener.h core/macglobalshortcutbackend.h devices/macdevicelister.h ui/macscreensaver.h diff --git a/src/core/macfslistener.h b/src/core/macfslistener.h new file mode 100644 index 000000000..e33aaf120 --- /dev/null +++ b/src/core/macfslistener.h @@ -0,0 +1,38 @@ +#ifndef MACFSLISTENER_H +#define MACFSLISTENER_H + +#include + +#include +#include + +class MacFSListener : public QObject { + Q_OBJECT + + public: + MacFSListener(); + void Init(); + + void AddPath(const QString& path); + + signals: + void PathChanged(const QString& path); + + private: + void UpdateStream(); + + static void EventStreamCallback( + ConstFSEventStreamRef stream, + void* user_data, + size_t num_events, + void* event_paths, + const FSEventStreamEventFlags event_flags[], + const FSEventStreamEventId event_ids[]); + + CFRunLoopRef run_loop_; + FSEventStreamRef stream_; + + QSet paths_; +}; + +#endif diff --git a/src/core/macfslistener.mm b/src/core/macfslistener.mm new file mode 100644 index 000000000..1c9d5d203 --- /dev/null +++ b/src/core/macfslistener.mm @@ -0,0 +1,75 @@ +#include "macfslistener.h" + +#include +#include +#include + +#include "core/logging.h" + +MacFSListener::MacFSListener() + : run_loop_(NULL), + stream_(NULL) { +} + +void MacFSListener::Init() { + run_loop_ = CFRunLoopGetCurrent(); +} + +void MacFSListener::EventStreamCallback( + ConstFSEventStreamRef stream, + void* user_data, + size_t num_events, + void* event_paths, + const FSEventStreamEventFlags event_flags[], + const FSEventStreamEventId event_ids[]) { + MacFSListener* me = reinterpret_cast(user_data); + char** paths = reinterpret_cast(event_paths); + for (int i = 0; i < num_events; ++i) { + QString path = QString::fromUtf8(paths[i]); + qLog(Debug) << "Something changed at:" << path; + emit me->PathChanged(path); + } +} + +void MacFSListener::AddPath(const QString& path) { + paths_.insert(path); + UpdateStream(); +} + +void MacFSListener::UpdateStream() { + if (stream_) { + FSEventStreamInvalidate(stream_); + stream_ = NULL; + } + + if (paths_.empty()) { + return; + } + + NSMutableArray* array = [[NSMutableArray alloc] init]; + + foreach (const QString& path, paths_) { + NSString* string = [[NSString alloc] initWithUTF8String: path.toUtf8().constData()]; + [array addObject: string]; + [string release]; + } + + FSEventStreamContext context; + memset(&context, 0, sizeof(context)); + context.info = this; + CFAbsoluteTime latency = 1.0; + + stream_ = FSEventStreamCreate( + NULL, + &EventStreamCallback, + &context, // Copied + (CFArrayRef)array, + kFSEventStreamEventIdSinceNow, + latency, + kFSEventStreamCreateFlagNone); + + FSEventStreamScheduleWithRunLoop(stream_, run_loop_, kCFRunLoopDefaultMode); + FSEventStreamStart(stream_); + + [array release]; +} From 3c867fb05c8fd31623d942d86d7d30891e55c08d Mon Sep 17 00:00:00 2001 From: John Maguire Date: Wed, 4 Jan 2012 15:26:22 +0000 Subject: [PATCH 08/40] Add QObject constructor. (cherry picked from commit 3f0c779308cfa5cca5193c740d3057a23ddcec25) --- src/core/macfslistener.h | 2 +- src/core/macfslistener.mm | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/core/macfslistener.h b/src/core/macfslistener.h index e33aaf120..f477751db 100644 --- a/src/core/macfslistener.h +++ b/src/core/macfslistener.h @@ -10,7 +10,7 @@ class MacFSListener : public QObject { Q_OBJECT public: - MacFSListener(); + explicit MacFSListener(QObject* parent = 0); void Init(); void AddPath(const QString& path); diff --git a/src/core/macfslistener.mm b/src/core/macfslistener.mm index 1c9d5d203..cf799bd89 100644 --- a/src/core/macfslistener.mm +++ b/src/core/macfslistener.mm @@ -6,8 +6,9 @@ #include "core/logging.h" -MacFSListener::MacFSListener() - : run_loop_(NULL), +MacFSListener::MacFSListener(QObject* parent) + : QObject(parent), + run_loop_(NULL), stream_(NULL) { } From e27568fbba902bd615aa7f07699bd8e56c4bd603 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Wed, 4 Jan 2012 15:33:12 +0000 Subject: [PATCH 09/40] Add scoped_nsobject from Chrome. (cherry picked from commit 0139f36e2db379ceb915c478f9e25813d94bdd51) --- src/core/macfslistener.mm | 14 ++-- src/core/scoped_nsobject.h | 160 +++++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+), 7 deletions(-) create mode 100644 src/core/scoped_nsobject.h diff --git a/src/core/macfslistener.mm b/src/core/macfslistener.mm index cf799bd89..4ae6c5d5a 100644 --- a/src/core/macfslistener.mm +++ b/src/core/macfslistener.mm @@ -5,6 +5,7 @@ #include #include "core/logging.h" +#include "core/scoped_nsobject.h" MacFSListener::MacFSListener(QObject* parent) : QObject(parent), @@ -40,6 +41,7 @@ void MacFSListener::AddPath(const QString& path) { void MacFSListener::UpdateStream() { if (stream_) { FSEventStreamInvalidate(stream_); + FSEventStreamRelease(stream_); stream_ = NULL; } @@ -47,12 +49,12 @@ void MacFSListener::UpdateStream() { return; } - NSMutableArray* array = [[NSMutableArray alloc] init]; + scoped_nsobject array([[NSMutableArray alloc] init]); foreach (const QString& path, paths_) { - NSString* string = [[NSString alloc] initWithUTF8String: path.toUtf8().constData()]; - [array addObject: string]; - [string release]; + scoped_nsobject string( + [[NSString alloc] initWithUTF8String: path.toUtf8().constData()]); + [array addObject: string.get()]; } FSEventStreamContext context; @@ -64,13 +66,11 @@ void MacFSListener::UpdateStream() { NULL, &EventStreamCallback, &context, // Copied - (CFArrayRef)array, + reinterpret_cast(array.get()), kFSEventStreamEventIdSinceNow, latency, kFSEventStreamCreateFlagNone); FSEventStreamScheduleWithRunLoop(stream_, run_loop_, kCFRunLoopDefaultMode); FSEventStreamStart(stream_); - - [array release]; } diff --git a/src/core/scoped_nsobject.h b/src/core/scoped_nsobject.h new file mode 100644 index 000000000..cd8271399 --- /dev/null +++ b/src/core/scoped_nsobject.h @@ -0,0 +1,160 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_MEMORY_SCOPED_NSOBJECT_H_ +#define BASE_MEMORY_SCOPED_NSOBJECT_H_ + +#import + +// scoped_nsobject<> is patterned after scoped_ptr<>, but maintains ownership +// of an NSObject subclass object. Style deviations here are solely for +// compatibility with scoped_ptr<>'s interface, with which everyone is already +// familiar. +// +// When scoped_nsobject<> takes ownership of an object (in the constructor or +// in reset()), it takes over the caller's existing ownership claim. The +// caller must own the object it gives to scoped_nsobject<>, and relinquishes +// an ownership claim to that object. scoped_nsobject<> does not call +// -retain. +// +// scoped_nsobject<> is not to be used for NSAutoreleasePools. For +// NSAutoreleasePools use ScopedNSAutoreleasePool from +// scoped_nsautorelease_pool.h instead. +// We check for bad uses of scoped_nsobject and NSAutoreleasePool at compile +// time with a template specialization (see below). +template +class scoped_nsobject { + public: + explicit scoped_nsobject(NST* object = nil) + : object_(object) { + } + + ~scoped_nsobject() { + [object_ release]; + } + + void reset(NST* object = nil) { + // We intentionally do not check that object != object_ as the caller must + // already have an ownership claim over whatever it gives to + // scoped_nsobject and ScopedCFTypeRef, whether it's in the constructor or + // in a call to reset(). In either case, it relinquishes that claim and + // the scoper assumes it. + [object_ release]; + object_ = object; + } + + bool operator==(NST* that) const { return object_ == that; } + bool operator!=(NST* that) const { return object_ != that; } + + operator NST*() const { + return object_; + } + + NST* get() const { + return object_; + } + + void swap(scoped_nsobject& that) { + NST* temp = that.object_; + that.object_ = object_; + object_ = temp; + } + + // scoped_nsobject<>::release() is like scoped_ptr<>::release. It is NOT + // a wrapper for [object_ release]. To force a scoped_nsobject<> object to + // call [object_ release], use scoped_nsobject<>::reset(). + NST* release() __attribute__((warn_unused_result)) { + NST* temp = object_; + object_ = nil; + return temp; + } + + private: + NST* object_; + + Q_DISABLE_COPY(scoped_nsobject); +}; + +// Free functions +template +void swap(scoped_nsobject& p1, scoped_nsobject& p2) { + p1.swap(p2); +} + +template +bool operator==(C* p1, const scoped_nsobject& p2) { + return p1 == p2.get(); +} + +template +bool operator!=(C* p1, const scoped_nsobject& p2) { + return p1 != p2.get(); +} + + +// Specialization to make scoped_nsobject work. +template<> +class scoped_nsobject { + public: + explicit scoped_nsobject(id object = nil) + : object_(object) { + } + + ~scoped_nsobject() { + [object_ release]; + } + + void reset(id object = nil) { + // We intentionally do not check that object != object_ as the caller must + // already have an ownership claim over whatever it gives to + // scoped_nsobject and ScopedCFTypeRef, whether it's in the constructor or + // in a call to reset(). In either case, it relinquishes that claim and + // the scoper assumes it. + [object_ release]; + object_ = object; + } + + bool operator==(id that) const { return object_ == that; } + bool operator!=(id that) const { return object_ != that; } + + operator id() const { + return object_; + } + + id get() const { + return object_; + } + + void swap(scoped_nsobject& that) { + id temp = that.object_; + that.object_ = object_; + object_ = temp; + } + + // scoped_nsobject<>::release() is like scoped_ptr<>::release. It is NOT + // a wrapper for [object_ release]. To force a scoped_nsobject<> object to + // call [object_ release], use scoped_nsobject<>::reset(). + id release() __attribute__((warn_unused_result)) { + id temp = object_; + object_ = nil; + return temp; + } + + private: + id object_; + + Q_DISABLE_COPY(scoped_nsobject); +}; + +// Do not use scoped_nsobject for NSAutoreleasePools, use +// ScopedNSAutoreleasePool instead. This is a compile time check. See details +// at top of header. +template<> +class scoped_nsobject { + private: + explicit scoped_nsobject(NSAutoreleasePool* object = nil); + Q_DISABLE_COPY(scoped_nsobject); +}; + +#endif // BASE_MEMORY_SCOPED_NSOBJECT_H_ From ea9a8ea2ed6480dcd8af0388243201e47ddba027 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Wed, 4 Jan 2012 15:34:52 +0000 Subject: [PATCH 10/40] Add copyright notice for Chromium code. (cherry picked from commit 6357cb074bec8eeed028d6fc6d18aed83d6a140b) --- debian/copyright | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/debian/copyright b/debian/copyright index dc5ee28be..fde23fc18 100644 --- a/debian/copyright +++ b/debian/copyright @@ -45,6 +45,10 @@ Files: src/core/fht.* Copyright: 2004, Melchior FRANZ License: GPL-2+ +Files: src/core/scoped_nsobject.h +Copyright: 2011, The Chromium Authors +License: BSD-Google + Files: 3rdparty/gmock/* Copyright: 2008, Google Inc. License: BSD-Google From ec2f57148b011d67fc397adf97ca18a021a2c066 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Thu, 5 Jan 2012 14:51:23 +0000 Subject: [PATCH 11/40] Use FSEvent-based filesystem watcher on Mac. (cherry picked from commit 9fdfb522254a0a6d3b9175c4d8de32a69f9371d8) --- src/CMakeLists.txt | 4 +++ src/core/filesystemwatcherinterface.cpp | 23 +++++++++++++++ src/core/filesystemwatcherinterface.h | 19 +++++++++++++ src/core/macfslistener.h | 4 ++- src/core/macfslistener.mm | 4 ++- src/core/qtfslistener.cpp | 12 ++++++++ src/core/qtfslistener.h | 19 +++++++++++++ src/library/library.cpp | 3 ++ src/library/librarywatcher.cpp | 37 ++++++++++--------------- src/library/librarywatcher.h | 13 +++++---- src/musicbrainz/musicdnsclient.cpp | 21 ++++++++++++-- 11 files changed, 126 insertions(+), 33 deletions(-) create mode 100644 src/core/filesystemwatcherinterface.cpp create mode 100644 src/core/filesystemwatcherinterface.h create mode 100644 src/core/qtfslistener.cpp create mode 100644 src/core/qtfslistener.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 443e70be6..4ef5790b6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -66,6 +66,7 @@ set(SOURCES core/deletefiles.cpp core/encoding.cpp core/filesystemmusicstorage.cpp + core/filesystemwatcherinterface.cpp core/fht.cpp core/fmpsparser.cpp core/globalshortcutbackend.cpp @@ -80,6 +81,7 @@ set(SOURCES core/organise.cpp core/organiseformat.cpp core/player.cpp + core/qtfslistener.cpp core/qxtglobalshortcutbackend.cpp core/scopedtransaction.cpp core/settingsprovider.cpp @@ -332,6 +334,7 @@ set(HEADERS core/crashreporting.h core/database.h core/deletefiles.h + core/filesystemwatcherinterface.h core/globalshortcuts.h core/globalshortcutbackend.h core/gnomeglobalshortcutbackend.h @@ -340,6 +343,7 @@ set(HEADERS core/network.h core/organise.h core/player.h + core/qtfslistener.h core/songloader.h core/taskmanager.h core/urlhandler.h diff --git a/src/core/filesystemwatcherinterface.cpp b/src/core/filesystemwatcherinterface.cpp new file mode 100644 index 000000000..074322e73 --- /dev/null +++ b/src/core/filesystemwatcherinterface.cpp @@ -0,0 +1,23 @@ +#include "filesystemwatcherinterface.h" + +#include "qtfslistener.h" + +#ifdef Q_OS_DARWIN +#include "macfslistener.h" +#endif + +FileSystemWatcherInterface::FileSystemWatcherInterface(QObject* parent) + : QObject(parent) { +} + +FileSystemWatcherInterface* FileSystemWatcherInterface::Create(QObject* parent) { + FileSystemWatcherInterface* ret; +#ifdef Q_OS_DARWIN + ret = new MacFSListener(parent); +#else + ret = new QtFSListener(parent); +#endif + + ret->Init(); + return ret; +} diff --git a/src/core/filesystemwatcherinterface.h b/src/core/filesystemwatcherinterface.h new file mode 100644 index 000000000..582391c02 --- /dev/null +++ b/src/core/filesystemwatcherinterface.h @@ -0,0 +1,19 @@ +#ifndef FILESYSTEMWATCHERINTERFACE_H +#define FILESYSTEMWATCHERINTERFACE_H + +#include + +class FileSystemWatcherInterface : public QObject { + Q_OBJECT + public: + FileSystemWatcherInterface(QObject* parent = 0); + virtual void Init() {} + virtual void AddPath(const QString& path) = 0; + + static FileSystemWatcherInterface* Create(QObject* parent = 0); + + signals: + void PathChanged(const QString& path); +}; + +#endif diff --git a/src/core/macfslistener.h b/src/core/macfslistener.h index f477751db..9e214232e 100644 --- a/src/core/macfslistener.h +++ b/src/core/macfslistener.h @@ -6,7 +6,9 @@ #include #include -class MacFSListener : public QObject { +#include "filesystemwatcherinterface.h" + +class MacFSListener : public FileSystemWatcherInterface { Q_OBJECT public: diff --git a/src/core/macfslistener.mm b/src/core/macfslistener.mm index 4ae6c5d5a..3e245ac0c 100644 --- a/src/core/macfslistener.mm +++ b/src/core/macfslistener.mm @@ -8,7 +8,7 @@ #include "core/scoped_nsobject.h" MacFSListener::MacFSListener(QObject* parent) - : QObject(parent), + : FileSystemWatcherInterface(parent), run_loop_(NULL), stream_(NULL) { } @@ -34,12 +34,14 @@ void MacFSListener::EventStreamCallback( } void MacFSListener::AddPath(const QString& path) { + Q_ASSERT(run_loop_); paths_.insert(path); UpdateStream(); } void MacFSListener::UpdateStream() { if (stream_) { + FSEventStreamStop(stream_); FSEventStreamInvalidate(stream_); FSEventStreamRelease(stream_); stream_ = NULL; diff --git a/src/core/qtfslistener.cpp b/src/core/qtfslistener.cpp new file mode 100644 index 000000000..0a136f779 --- /dev/null +++ b/src/core/qtfslistener.cpp @@ -0,0 +1,12 @@ +#include "qtfslistener.h" + +QtFSListener::QtFSListener(QObject* parent) + : FileSystemWatcherInterface(parent), + watcher_(this) { + connect(&watcher_, SIGNAL(directoryChanged(const QString&)), + SIGNAL(PathChanged(const QString&))); +} + +void QtFSListener::AddPath(const QString& path) { + watcher_.addPath(path); +} diff --git a/src/core/qtfslistener.h b/src/core/qtfslistener.h new file mode 100644 index 000000000..8b2dec126 --- /dev/null +++ b/src/core/qtfslistener.h @@ -0,0 +1,19 @@ +#ifndef QTFSLISTENER_H +#define QTFSLISTENER_H + +#include "filesystemwatcherinterface.h" + +#include + +class QtFSListener : public FileSystemWatcherInterface { + Q_OBJECT + public: + QtFSListener(QObject* parent); + virtual void AddPath(const QString& path); + + private: + QFileSystemWatcher watcher_; + +}; + +#endif diff --git a/src/library/library.cpp b/src/library/library.cpp index 64b60d3a5..1f8d14322 100644 --- a/src/library/library.cpp +++ b/src/library/library.cpp @@ -16,9 +16,11 @@ */ #include "library.h" + #include "librarymodel.h" #include "librarybackend.h" #include "core/database.h" +#include "core/filesystemwatcherinterface.h" #include "smartplaylists/generator.h" #include "smartplaylists/querygenerator.h" #include "smartplaylists/search.h" @@ -119,6 +121,7 @@ void Library::WatcherInitialised() { watcher->set_backend(backend_); watcher->set_task_manager(task_manager_); + watcher->set_filesystem_watcher(FileSystemWatcherInterface::Create()); connect(backend_, SIGNAL(DirectoryDiscovered(Directory,SubdirectoryList)), watcher, SLOT(AddDirectory(Directory,SubdirectoryList))); diff --git a/src/library/librarywatcher.cpp b/src/library/librarywatcher.cpp index da7e86c7a..4396c4f32 100644 --- a/src/library/librarywatcher.cpp +++ b/src/library/librarywatcher.cpp @@ -16,12 +16,13 @@ */ #include "librarywatcher.h" + #include "librarybackend.h" +#include "core/filesystemwatcherinterface.h" #include "core/logging.h" #include "core/taskmanager.h" #include "playlistparsers/cueparser.h" -#include #include #include #include @@ -48,6 +49,7 @@ LibraryWatcher::LibraryWatcher(QObject* parent) : QObject(parent), backend_(NULL), task_manager_(NULL), + fs_watcher_(NULL), stop_requested_(false), scan_on_startup_(true), monitor_(true), @@ -113,7 +115,7 @@ LibraryWatcher::ScanTransaction::~ScanTransaction() { if (watcher_->monitor_) { // Watch the new subdirectories foreach (const Subdirectory& subdir, new_subdirs) { - watcher_->AddWatch(watcher_->watched_dirs_[dir_].watcher, subdir.path); + watcher_->AddWatch(subdir.path); } } } @@ -183,8 +185,6 @@ SubdirectoryList LibraryWatcher::ScanTransaction::GetAllSubdirs() { void LibraryWatcher::AddDirectory(const Directory& dir, const SubdirectoryList& subdirs) { DirData data; data.dir = dir; - data.watcher = new QFileSystemWatcher(this); - connect(data.watcher, SIGNAL(directoryChanged(QString)), SLOT(DirectoryChanged(QString))); watched_dirs_[dir.id] = data; if (subdirs.isEmpty()) { @@ -207,7 +207,7 @@ void LibraryWatcher::AddDirectory(const Directory& dir, const SubdirectoryList& ScanSubdirectory(subdir.path, subdir, &transaction); if (monitor_) - AddWatch(data.watcher, subdir.path); + AddWatch(subdir.path); } } @@ -546,18 +546,16 @@ uint LibraryWatcher::GetMtimeForCue(const QString& cue_path) { : 0; } -void LibraryWatcher::AddWatch(QFileSystemWatcher* w, const QString& path) { +void LibraryWatcher::AddWatch(const QString& path) { if (!QFile::exists(path)) return; - w->addPath(path); + connect(fs_watcher_, SIGNAL(PathChanged(const QString&)), this, + SLOT(DirectoryChanged(const QString&)), Qt::UniqueConnection); + fs_watcher_->AddPath(path); } void LibraryWatcher::RemoveDirectory(const Directory& dir) { - if (watched_dirs_.contains(dir.id)) { - delete watched_dirs_[dir.id].watcher; - } - rescan_queue_.remove(dir.id); watched_dirs_.remove(dir.id); } @@ -575,13 +573,9 @@ bool LibraryWatcher::FindSongByPath(const SongList& list, const QString& path, S void LibraryWatcher::DirectoryChanged(const QString &subdir) { // Find what dir it was in - QFileSystemWatcher* watcher = qobject_cast(sender()); - if (!watcher) - return; - Directory dir; foreach (const DirData& info, watched_dirs_) { - if (info.watcher == watcher) + if (subdir.startsWith(info.dir.path)) dir = info.dir; } @@ -689,7 +683,7 @@ void LibraryWatcher::ReloadSettings() { s.beginGroup(kSettingsGroup); scan_on_startup_ = s.value("startup_scan", true).toBool(); monitor_ = s.value("monitor", true).toBool(); - + best_image_filters_.clear(); QStringList filters = s.value("cover_art_patterns", QStringList() << "front" << "cover").toStringList(); @@ -698,18 +692,15 @@ void LibraryWatcher::ReloadSettings() { if (!s.isEmpty()) best_image_filters_ << s; } - + if (!monitor_ && was_monitoring_before) { - // Remove all directories from all QFileSystemWatchers - foreach (const DirData& data, watched_dirs_.values()) { - data.watcher->removePaths(data.watcher->directories()); - } + // TODO: Remove all directories from watcher. } else if (monitor_ && !was_monitoring_before) { // Add all directories to all QFileSystemWatchers again foreach (const DirData& data, watched_dirs_.values()) { SubdirectoryList subdirs = backend_->SubdirsInDirectory(data.dir.id); foreach (const Subdirectory& subdir, subdirs) { - AddWatch(data.watcher, subdir.path); + AddWatch(subdir.path); } } } diff --git a/src/library/librarywatcher.h b/src/library/librarywatcher.h index 92f7f68c6..f47c6207f 100644 --- a/src/library/librarywatcher.h +++ b/src/library/librarywatcher.h @@ -29,6 +29,7 @@ class QFileSystemWatcher; class QTimer; class CueParser; +class FileSystemWatcherInterface; class LibraryBackend; class TaskManager; @@ -42,8 +43,9 @@ class LibraryWatcher : public QObject { void set_backend(LibraryBackend* backend) { backend_ = backend; } void set_task_manager(TaskManager* task_manager) { task_manager_ = task_manager; } + void set_filesystem_watcher(FileSystemWatcherInterface* watcher) { fs_watcher_ = watcher; } void set_device_name(const QString& device_name) { device_name_ = device_name; } - + void IncrementalScanAsync(); void FullScanAsync(); void SetRescanPausedAsync(bool pause); @@ -144,7 +146,7 @@ class LibraryWatcher : public QObject { inline static QString DirectoryPart( const QString &fileName ); QString PickBestImage(const QStringList& images); QString ImageForSong(const QString& path, QMap& album_art); - void AddWatch(QFileSystemWatcher* w, const QString& path); + void AddWatch(const QString& path); uint GetMtimeForCue(const QString& cue_path); void PerformScan(bool incremental, bool ignore_mtimes); @@ -172,20 +174,21 @@ class LibraryWatcher : public QObject { // One of these gets stored for each Directory we're watching struct DirData { Directory dir; - QFileSystemWatcher* watcher; }; LibraryBackend* backend_; TaskManager* task_manager_; QString device_name_; - + + FileSystemWatcherInterface* fs_watcher_; + /* A list of words use to try to identify the (likely) best image * found in an directory to use as cover artwork. * e.g. using ["front", "cover"] would identify front.jpg and * exclude back.jpg. */ QStringList best_image_filters_; - + bool stop_requested_; bool scan_on_startup_; bool monitor_; diff --git a/src/musicbrainz/musicdnsclient.cpp b/src/musicbrainz/musicdnsclient.cpp index bd777d86e..ba8ec2d9f 100644 --- a/src/musicbrainz/musicdnsclient.cpp +++ b/src/musicbrainz/musicdnsclient.cpp @@ -16,14 +16,18 @@ */ #include "musicdnsclient.h" -#include "core/network.h" +#include #include #include #include #include -const char* MusicDnsClient::kClientId = "c44f70e49000dd7c0d1388bff2bf4152"; +#include "core/logging.h" +#include "core/network.h" + +//const char* MusicDnsClient::kClientId = "c44f70e49000dd7c0d1388bff2bf4152"; +const char* MusicDnsClient::kClientId = "0736ac2cd889ef77f26f6b5e3fb8a09c"; const char* MusicDnsClient::kUrl = "http://ofa.musicdns.org/ofa/1/track"; const int MusicDnsClient::kDefaultTimeout = 5000; // msec @@ -49,10 +53,12 @@ void MusicDnsClient::Start(int id, const QString& fingerprint, int duration_msec << Param("cvr", QString("%1 %2").arg(QCoreApplication::applicationName(), QCoreApplication::applicationVersion())) << Param("dur", QString::number(duration_msec)) + << Param("lkt", "1") << Param("fmt", "unknown") << Param("fpt", fingerprint) << Param("gnr", "unknown") << Param("rmd", "1") + << Param("rmt", "0") << Param("tnm", "0") << Param("ttl", "unknown") << Param("yrr", "0"); @@ -61,6 +67,8 @@ void MusicDnsClient::Start(int id, const QString& fingerprint, int duration_msec url.setQueryItems(parameters); QNetworkRequest req(url); + qLog(Debug) << url; + QNetworkReply* reply = network_->get(req); connect(reply, SIGNAL(finished()), SLOT(RequestFinished())); requests_[reply] = id; @@ -90,12 +98,19 @@ void MusicDnsClient::RequestFinished() { int id = requests_.take(reply); + qLog(Debug) << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) { emit Finished(id, QString()); return; } - QXmlStreamReader reader(reply); + QByteArray data = reply->readAll(); + qLog(Debug) << data; + QBuffer buffer(&data); + buffer.open(QIODevice::ReadOnly); + + QXmlStreamReader reader(&buffer); while (!reader.atEnd()) { if (reader.readNext() == QXmlStreamReader::StartElement && reader.name() == "puid") { QString puid = reader.attributes().value("id").toString(); From b5ff9955a87009ebb6dc48c90657876a7fe69bad Mon Sep 17 00:00:00 2001 From: John Maguire Date: Thu, 5 Jan 2012 15:01:43 +0000 Subject: [PATCH 12/40] Disable watching for FS updates when requested. (cherry picked from commit 55e9fd8dc39df3a8884656aec6fc1cebf1268ccc) --- src/core/filesystemwatcherinterface.h | 1 + src/core/macfslistener.h | 2 +- src/core/macfslistener.mm | 5 +++++ src/core/qtfslistener.cpp | 7 +++++++ src/core/qtfslistener.h | 1 + src/library/librarywatcher.cpp | 2 +- 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/core/filesystemwatcherinterface.h b/src/core/filesystemwatcherinterface.h index 582391c02..4663b46c8 100644 --- a/src/core/filesystemwatcherinterface.h +++ b/src/core/filesystemwatcherinterface.h @@ -9,6 +9,7 @@ class FileSystemWatcherInterface : public QObject { FileSystemWatcherInterface(QObject* parent = 0); virtual void Init() {} virtual void AddPath(const QString& path) = 0; + virtual void Clear() = 0; static FileSystemWatcherInterface* Create(QObject* parent = 0); diff --git a/src/core/macfslistener.h b/src/core/macfslistener.h index 9e214232e..de3602ad0 100644 --- a/src/core/macfslistener.h +++ b/src/core/macfslistener.h @@ -14,8 +14,8 @@ class MacFSListener : public FileSystemWatcherInterface { public: explicit MacFSListener(QObject* parent = 0); void Init(); - void AddPath(const QString& path); + void Clear(); signals: void PathChanged(const QString& path); diff --git a/src/core/macfslistener.mm b/src/core/macfslistener.mm index 3e245ac0c..88d6d1161 100644 --- a/src/core/macfslistener.mm +++ b/src/core/macfslistener.mm @@ -39,6 +39,11 @@ void MacFSListener::AddPath(const QString& path) { UpdateStream(); } +void MacFSListener::Clear() { + paths_.clear(); + UpdateStream(); +} + void MacFSListener::UpdateStream() { if (stream_) { FSEventStreamStop(stream_); diff --git a/src/core/qtfslistener.cpp b/src/core/qtfslistener.cpp index 0a136f779..5b8560a55 100644 --- a/src/core/qtfslistener.cpp +++ b/src/core/qtfslistener.cpp @@ -1,5 +1,7 @@ #include "qtfslistener.h" +#include + QtFSListener::QtFSListener(QObject* parent) : FileSystemWatcherInterface(parent), watcher_(this) { @@ -10,3 +12,8 @@ QtFSListener::QtFSListener(QObject* parent) void QtFSListener::AddPath(const QString& path) { watcher_.addPath(path); } + +void QtFSListener::Clear() { + watcher_.removePaths(watcher_.directories()); + watcher_.removePaths(watcher_.files()); +} diff --git a/src/core/qtfslistener.h b/src/core/qtfslistener.h index 8b2dec126..cb3b737cb 100644 --- a/src/core/qtfslistener.h +++ b/src/core/qtfslistener.h @@ -10,6 +10,7 @@ class QtFSListener : public FileSystemWatcherInterface { public: QtFSListener(QObject* parent); virtual void AddPath(const QString& path); + virtual void Clear(); private: QFileSystemWatcher watcher_; diff --git a/src/library/librarywatcher.cpp b/src/library/librarywatcher.cpp index 4396c4f32..74457d239 100644 --- a/src/library/librarywatcher.cpp +++ b/src/library/librarywatcher.cpp @@ -694,7 +694,7 @@ void LibraryWatcher::ReloadSettings() { } if (!monitor_ && was_monitoring_before) { - // TODO: Remove all directories from watcher. + fs_watcher_->Clear(); } else if (monitor_ && !was_monitoring_before) { // Add all directories to all QFileSystemWatchers again foreach (const DirData& data, watched_dirs_.values()) { From fea20e9c29e0318b0775637eb430bf11ce718b81 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Thu, 5 Jan 2012 15:06:32 +0000 Subject: [PATCH 13/40] Revert irrelevant musicdns changes. (cherry picked from commit 047bec831bcc97cdc1986177da8b8f302ea967a0) --- src/musicbrainz/musicdnsclient.cpp | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/musicbrainz/musicdnsclient.cpp b/src/musicbrainz/musicdnsclient.cpp index ba8ec2d9f..bd777d86e 100644 --- a/src/musicbrainz/musicdnsclient.cpp +++ b/src/musicbrainz/musicdnsclient.cpp @@ -16,18 +16,14 @@ */ #include "musicdnsclient.h" +#include "core/network.h" -#include #include #include #include #include -#include "core/logging.h" -#include "core/network.h" - -//const char* MusicDnsClient::kClientId = "c44f70e49000dd7c0d1388bff2bf4152"; -const char* MusicDnsClient::kClientId = "0736ac2cd889ef77f26f6b5e3fb8a09c"; +const char* MusicDnsClient::kClientId = "c44f70e49000dd7c0d1388bff2bf4152"; const char* MusicDnsClient::kUrl = "http://ofa.musicdns.org/ofa/1/track"; const int MusicDnsClient::kDefaultTimeout = 5000; // msec @@ -53,12 +49,10 @@ void MusicDnsClient::Start(int id, const QString& fingerprint, int duration_msec << Param("cvr", QString("%1 %2").arg(QCoreApplication::applicationName(), QCoreApplication::applicationVersion())) << Param("dur", QString::number(duration_msec)) - << Param("lkt", "1") << Param("fmt", "unknown") << Param("fpt", fingerprint) << Param("gnr", "unknown") << Param("rmd", "1") - << Param("rmt", "0") << Param("tnm", "0") << Param("ttl", "unknown") << Param("yrr", "0"); @@ -67,8 +61,6 @@ void MusicDnsClient::Start(int id, const QString& fingerprint, int duration_msec url.setQueryItems(parameters); QNetworkRequest req(url); - qLog(Debug) << url; - QNetworkReply* reply = network_->get(req); connect(reply, SIGNAL(finished()), SLOT(RequestFinished())); requests_[reply] = id; @@ -98,19 +90,12 @@ void MusicDnsClient::RequestFinished() { int id = requests_.take(reply); - qLog(Debug) << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); - if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) { emit Finished(id, QString()); return; } - QByteArray data = reply->readAll(); - qLog(Debug) << data; - QBuffer buffer(&data); - buffer.open(QIODevice::ReadOnly); - - QXmlStreamReader reader(&buffer); + QXmlStreamReader reader(reply); while (!reader.atEnd()) { if (reader.readNext() == QXmlStreamReader::StartElement && reader.name() == "puid") { QString puid = reader.attributes().value("id").toString(); From a4ced28a852ee2efdd0e366241ebd120576da7a5 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Thu, 5 Jan 2012 15:08:15 +0000 Subject: [PATCH 14/40] Add copyright headers. (cherry picked from commit 97f3885f58420348a44d73cba024ac7114793928) --- src/core/filesystemwatcherinterface.cpp | 17 +++++++++++++++++ src/core/filesystemwatcherinterface.h | 17 +++++++++++++++++ src/core/macfslistener.h | 17 +++++++++++++++++ src/core/macfslistener.mm | 17 +++++++++++++++++ src/core/qtfslistener.cpp | 17 +++++++++++++++++ src/core/qtfslistener.h | 17 +++++++++++++++++ 6 files changed, 102 insertions(+) diff --git a/src/core/filesystemwatcherinterface.cpp b/src/core/filesystemwatcherinterface.cpp index 074322e73..b6afcb0af 100644 --- a/src/core/filesystemwatcherinterface.cpp +++ b/src/core/filesystemwatcherinterface.cpp @@ -1,3 +1,20 @@ +/* This file is part of Clementine. + Copyright 2012, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + #include "filesystemwatcherinterface.h" #include "qtfslistener.h" diff --git a/src/core/filesystemwatcherinterface.h b/src/core/filesystemwatcherinterface.h index 4663b46c8..3c260d784 100644 --- a/src/core/filesystemwatcherinterface.h +++ b/src/core/filesystemwatcherinterface.h @@ -1,3 +1,20 @@ +/* This file is part of Clementine. + Copyright 2012, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + #ifndef FILESYSTEMWATCHERINTERFACE_H #define FILESYSTEMWATCHERINTERFACE_H diff --git a/src/core/macfslistener.h b/src/core/macfslistener.h index de3602ad0..7d98ebae1 100644 --- a/src/core/macfslistener.h +++ b/src/core/macfslistener.h @@ -1,3 +1,20 @@ +/* This file is part of Clementine. + Copyright 2012, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + #ifndef MACFSLISTENER_H #define MACFSLISTENER_H diff --git a/src/core/macfslistener.mm b/src/core/macfslistener.mm index 88d6d1161..e28c2885f 100644 --- a/src/core/macfslistener.mm +++ b/src/core/macfslistener.mm @@ -1,3 +1,20 @@ +/* This file is part of Clementine. + Copyright 2012, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + #include "macfslistener.h" #include diff --git a/src/core/qtfslistener.cpp b/src/core/qtfslistener.cpp index 5b8560a55..af1356bda 100644 --- a/src/core/qtfslistener.cpp +++ b/src/core/qtfslistener.cpp @@ -1,3 +1,20 @@ +/* This file is part of Clementine. + Copyright 2012, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + #include "qtfslistener.h" #include diff --git a/src/core/qtfslistener.h b/src/core/qtfslistener.h index cb3b737cb..fcb8d9a69 100644 --- a/src/core/qtfslistener.h +++ b/src/core/qtfslistener.h @@ -1,3 +1,20 @@ +/* This file is part of Clementine. + Copyright 2012, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + #ifndef QTFSLISTENER_H #define QTFSLISTENER_H From f6c229c5e6b38c2e85f6254e9eaa6aa8ad4bccef Mon Sep 17 00:00:00 2001 From: John Maguire Date: Thu, 5 Jan 2012 15:56:46 +0000 Subject: [PATCH 15/40] Add more robust subdirectory detection in LibraryWatcher. (cherry picked from commit 761737eb4df64b0cff4b71fe261f9376eaf6ff42) --- src/core/macfslistener.mm | 3 +++ src/library/librarywatcher.cpp | 17 +++++++++-------- src/library/librarywatcher.h | 18 ++++++++---------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/core/macfslistener.mm b/src/core/macfslistener.mm index e28c2885f..6d0326710 100644 --- a/src/core/macfslistener.mm +++ b/src/core/macfslistener.mm @@ -46,6 +46,9 @@ void MacFSListener::EventStreamCallback( for (int i = 0; i < num_events; ++i) { QString path = QString::fromUtf8(paths[i]); qLog(Debug) << "Something changed at:" << path; + if (path.endsWith('/')) { + path.chop(1); + } emit me->PathChanged(path); } } diff --git a/src/library/librarywatcher.cpp b/src/library/librarywatcher.cpp index 74457d239..b99366c09 100644 --- a/src/library/librarywatcher.cpp +++ b/src/library/librarywatcher.cpp @@ -115,7 +115,7 @@ LibraryWatcher::ScanTransaction::~ScanTransaction() { if (watcher_->monitor_) { // Watch the new subdirectories foreach (const Subdirectory& subdir, new_subdirs) { - watcher_->AddWatch(subdir.path); + watcher_->AddWatch(watcher_->watched_dirs_[dir_], subdir.path); } } } @@ -207,7 +207,7 @@ void LibraryWatcher::AddDirectory(const Directory& dir, const SubdirectoryList& ScanSubdirectory(subdir.path, subdir, &transaction); if (monitor_) - AddWatch(subdir.path); + AddWatch(data, subdir.path); } } @@ -546,13 +546,14 @@ uint LibraryWatcher::GetMtimeForCue(const QString& cue_path) { : 0; } -void LibraryWatcher::AddWatch(const QString& path) { +void LibraryWatcher::AddWatch(DirData dir, const QString& path) { if (!QFile::exists(path)) return; connect(fs_watcher_, SIGNAL(PathChanged(const QString&)), this, SLOT(DirectoryChanged(const QString&)), Qt::UniqueConnection); fs_watcher_->AddPath(path); + subdir_mapping_[path] = dir; } void LibraryWatcher::RemoveDirectory(const Directory& dir) { @@ -573,11 +574,11 @@ bool LibraryWatcher::FindSongByPath(const SongList& list, const QString& path, S void LibraryWatcher::DirectoryChanged(const QString &subdir) { // Find what dir it was in - Directory dir; - foreach (const DirData& info, watched_dirs_) { - if (subdir.startsWith(info.dir.path)) - dir = info.dir; + QHash::const_iterator it = subdir_mapping_.constFind(subdir); + if (it == subdir_mapping_.constEnd()) { + return; } + Directory dir = it->dir; qLog(Debug) << "Subdir" << subdir << "changed under directory" << dir.path << "id" << dir.id; @@ -700,7 +701,7 @@ void LibraryWatcher::ReloadSettings() { foreach (const DirData& data, watched_dirs_.values()) { SubdirectoryList subdirs = backend_->SubdirsInDirectory(data.dir.id); foreach (const Subdirectory& subdir, subdirs) { - AddWatch(subdir.path); + AddWatch(data, subdir.path); } } } diff --git a/src/library/librarywatcher.h b/src/library/librarywatcher.h index f47c6207f..024acc98f 100644 --- a/src/library/librarywatcher.h +++ b/src/library/librarywatcher.h @@ -21,6 +21,7 @@ #include "directory.h" #include "core/song.h" +#include #include #include #include @@ -140,13 +141,18 @@ class LibraryWatcher : public QObject { ScanTransaction* t, bool force_noincremental = false); private: + // One of these gets stored for each Directory we're watching + struct DirData { + Directory dir; + }; + static bool FindSongByPath(const SongList& list, const QString& path, Song* out); inline static QString NoExtensionPart( const QString &fileName ); inline static QString ExtensionPart( const QString &fileName ); inline static QString DirectoryPart( const QString &fileName ); QString PickBestImage(const QStringList& images); QString ImageForSong(const QString& path, QMap& album_art); - void AddWatch(const QString& path); + void AddWatch(DirData dir, const QString& path); uint GetMtimeForCue(const QString& cue_path); void PerformScan(bool incremental, bool ignore_mtimes); @@ -171,16 +177,12 @@ class LibraryWatcher : public QObject { const QString& matching_cue, QSet* cues_processed); private: - // One of these gets stored for each Directory we're watching - struct DirData { - Directory dir; - }; - LibraryBackend* backend_; TaskManager* task_manager_; QString device_name_; FileSystemWatcherInterface* fs_watcher_; + QHash subdir_mapping_; /* A list of words use to try to identify the (likely) best image * found in an directory to use as cover artwork. @@ -203,10 +205,6 @@ class LibraryWatcher : public QObject { CueParser* cue_parser_; static QStringList sValidImages; - - #ifdef Q_OS_DARWIN - static const int kMaxWatches = 100; - #endif }; inline QString LibraryWatcher::NoExtensionPart( const QString &fileName ) { From 2a72d17f382f7a6a036bdd3627f357e6a9997545 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Thu, 5 Jan 2012 16:11:39 +0000 Subject: [PATCH 16/40] const& and tweaks to Mac directory canonicalisation. (cherry picked from commit 483c36748e5896019d1ec197d03feeff78ddcd16) --- src/core/macfslistener.mm | 2 +- src/library/librarywatcher.cpp | 2 +- src/library/librarywatcher.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/macfslistener.mm b/src/core/macfslistener.mm index 6d0326710..1fa315fb5 100644 --- a/src/core/macfslistener.mm +++ b/src/core/macfslistener.mm @@ -46,7 +46,7 @@ void MacFSListener::EventStreamCallback( for (int i = 0; i < num_events; ++i) { QString path = QString::fromUtf8(paths[i]); qLog(Debug) << "Something changed at:" << path; - if (path.endsWith('/')) { + while (path.endsWith('/')) { path.chop(1); } emit me->PathChanged(path); diff --git a/src/library/librarywatcher.cpp b/src/library/librarywatcher.cpp index b99366c09..41afe69be 100644 --- a/src/library/librarywatcher.cpp +++ b/src/library/librarywatcher.cpp @@ -546,7 +546,7 @@ uint LibraryWatcher::GetMtimeForCue(const QString& cue_path) { : 0; } -void LibraryWatcher::AddWatch(DirData dir, const QString& path) { +void LibraryWatcher::AddWatch(const DirData& dir, const QString& path) { if (!QFile::exists(path)) return; diff --git a/src/library/librarywatcher.h b/src/library/librarywatcher.h index 024acc98f..72b69ca16 100644 --- a/src/library/librarywatcher.h +++ b/src/library/librarywatcher.h @@ -152,7 +152,7 @@ class LibraryWatcher : public QObject { inline static QString DirectoryPart( const QString &fileName ); QString PickBestImage(const QStringList& images); QString ImageForSong(const QString& path, QMap& album_art); - void AddWatch(DirData dir, const QString& path); + void AddWatch(const DirData& dir, const QString& path); uint GetMtimeForCue(const QString& cue_path); void PerformScan(bool incremental, bool ignore_mtimes); From f02732e1382919baf42d976cb3c3be11a7314192 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 6 Jan 2012 15:55:50 +0000 Subject: [PATCH 17/40] Add Chromaprint to 3rdparty. (cherry picked from commit 1bcbc2ed3e9547f73c0cc793070d0940fba06371) --- 3rdparty/chromaprint/.gitignore | 38 ++ 3rdparty/chromaprint/CHANGES.txt | 5 + 3rdparty/chromaprint/CMakeLists.txt | 158 ++++++ 3rdparty/chromaprint/COPYING.txt | 502 ++++++++++++++++++ 3rdparty/chromaprint/NEWS.txt | 44 ++ 3rdparty/chromaprint/README.txt | 96 ++++ .../chromaprint/cmake/modules/FindFFTW3.cmake | 133 +++++ .../cmake/modules/FindFFmpeg.cmake | 128 +++++ .../chromaprint/cmake/modules/FindGTest.cmake | 175 ++++++ .../cmake/modules/FindTaglib.cmake | 135 +++++ 3rdparty/chromaprint/config.h.in | 7 + 3rdparty/chromaprint/examples/CMakeLists.txt | 39 ++ .../examples/ffmpeg/audioconvert.h | 118 ++++ .../chromaprint/examples/ffmpeg/samplefmt.h | 156 ++++++ 3rdparty/chromaprint/examples/fpcalc.c | 303 +++++++++++ 3rdparty/chromaprint/libchromaprint.pc.cmake | 12 + 3rdparty/chromaprint/src/CMakeLists.txt | 74 +++ 3rdparty/chromaprint/src/audio_consumer.h | 38 ++ 3rdparty/chromaprint/src/audio_processor.cpp | 191 +++++++ 3rdparty/chromaprint/src/audio_processor.h | 87 +++ 3rdparty/chromaprint/src/avresample/avcodec.h | 101 ++++ 3rdparty/chromaprint/src/avresample/dsputil.h | 1 + .../chromaprint/src/avresample/resample2.c | 320 +++++++++++ 3rdparty/chromaprint/src/base64.cpp | 92 ++++ 3rdparty/chromaprint/src/base64.h | 35 ++ 3rdparty/chromaprint/src/bit_string_reader.h | 69 +++ 3rdparty/chromaprint/src/bit_string_writer.h | 77 +++ 3rdparty/chromaprint/src/chroma.cpp | 95 ++++ 3rdparty/chromaprint/src/chroma.h | 68 +++ 3rdparty/chromaprint/src/chroma_filter.cpp | 69 +++ 3rdparty/chromaprint/src/chroma_filter.h | 54 ++ 3rdparty/chromaprint/src/chroma_normalizer.h | 55 ++ 3rdparty/chromaprint/src/chroma_resampler.cpp | 62 +++ 3rdparty/chromaprint/src/chroma_resampler.h | 52 ++ 3rdparty/chromaprint/src/chromaprint.cpp | 150 ++++++ 3rdparty/chromaprint/src/chromaprint.h | 222 ++++++++ 3rdparty/chromaprint/src/classifier.h | 61 +++ 3rdparty/chromaprint/src/combined_buffer.h | 176 ++++++ 3rdparty/chromaprint/src/debug.h | 42 ++ 3rdparty/chromaprint/src/decoder.h | 15 + 3rdparty/chromaprint/src/ext/audio_dumper.h | 30 ++ 3rdparty/chromaprint/src/ext/ffmpeg_decoder.h | 230 ++++++++ 3rdparty/chromaprint/src/ext/image_utils.cpp | 27 + 3rdparty/chromaprint/src/ext/image_utils.h | 108 ++++ 3rdparty/chromaprint/src/ext/sox_decoder.h | 101 ++++ .../chromaprint/src/feature_vector_consumer.h | 39 ++ 3rdparty/chromaprint/src/fft.cpp | 77 +++ 3rdparty/chromaprint/src/fft.h | 62 +++ 3rdparty/chromaprint/src/fft_frame.h | 69 +++ 3rdparty/chromaprint/src/fft_frame_consumer.h | 38 ++ 3rdparty/chromaprint/src/fft_lib.h | 40 ++ 3rdparty/chromaprint/src/fft_lib_avfft.cpp | 60 +++ 3rdparty/chromaprint/src/fft_lib_avfft.h | 53 ++ 3rdparty/chromaprint/src/fft_lib_fftw3.cpp | 58 ++ 3rdparty/chromaprint/src/fft_lib_fftw3.h | 51 ++ 3rdparty/chromaprint/src/fft_lib_vdsp.cpp | 61 +++ 3rdparty/chromaprint/src/fft_lib_vdsp.h | 52 ++ 3rdparty/chromaprint/src/filter.cpp | 47 ++ 3rdparty/chromaprint/src/filter.h | 67 +++ 3rdparty/chromaprint/src/filter_utils.h | 136 +++++ .../src/fingerprint_calculator.cpp | 67 +++ .../chromaprint/src/fingerprint_calculator.h | 51 ++ .../src/fingerprint_compressor.cpp | 92 ++++ .../chromaprint/src/fingerprint_compressor.h | 59 ++ .../src/fingerprint_decompressor.cpp | 99 ++++ .../src/fingerprint_decompressor.h | 56 ++ 3rdparty/chromaprint/src/fingerprinter.cpp | 97 ++++ 3rdparty/chromaprint/src/fingerprinter.h | 78 +++ .../src/fingerprinter_configuration.cpp | 107 ++++ .../src/fingerprinter_configuration.h | 126 +++++ 3rdparty/chromaprint/src/foo.cpp | 0 3rdparty/chromaprint/src/image.h | 74 +++ 3rdparty/chromaprint/src/image_builder.cpp | 43 ++ 3rdparty/chromaprint/src/image_builder.h | 66 +++ 3rdparty/chromaprint/src/integral_image.cpp | 49 ++ 3rdparty/chromaprint/src/integral_image.h | 87 +++ 3rdparty/chromaprint/src/lloyds.cpp | 111 ++++ 3rdparty/chromaprint/src/lloyds.h | 15 + 3rdparty/chromaprint/src/quantizer.h | 76 +++ 3rdparty/chromaprint/src/silence_remover.cpp | 65 +++ 3rdparty/chromaprint/src/silence_remover.h | 59 ++ 3rdparty/chromaprint/src/sox_audio_source.cpp | 71 +++ 3rdparty/chromaprint/src/sox_audio_source.h | 29 + .../chromaprint/src/spectral_centroid.cpp | 91 ++++ 3rdparty/chromaprint/src/spectral_centroid.h | 59 ++ 3rdparty/chromaprint/src/spectrum.cpp | 88 +++ 3rdparty/chromaprint/src/spectrum.h | 59 ++ 3rdparty/chromaprint/src/utils.h | 154 ++++++ 3rdparty/chromaprint/tests/CMakeLists.txt | 41 ++ 3rdparty/chromaprint/tests/audio_buffer.h | 21 + .../tests/data/test_mono_11025.raw | Bin 0 -> 44080 bytes .../tests/data/test_mono_44100.raw | Bin 0 -> 176400 bytes .../chromaprint/tests/data/test_mono_8000.raw | Bin 0 -> 31982 bytes .../tests/data/test_stereo_44100.raw | Bin 0 -> 352800 bytes 3rdparty/chromaprint/tests/main.cpp | 8 + 3rdparty/chromaprint/tests/test_api.cpp | 99 ++++ .../tests/test_audio_processor.cpp | 114 ++++ 3rdparty/chromaprint/tests/test_base64.cpp | 56 ++ .../tests/test_bit_string_reader.cpp | 47 ++ .../tests/test_bit_string_writer.cpp | 53 ++ 3rdparty/chromaprint/tests/test_chroma.cpp | 125 +++++ .../chromaprint/tests/test_chroma_filter.cpp | 74 +++ .../tests/test_chroma_resampler.cpp | 48 ++ .../chromaprint/tests/test_chromaprint.cpp | 67 +++ .../tests/test_combined_buffer.cpp | 95 ++++ 3rdparty/chromaprint/tests/test_filter.cpp | 25 + .../chromaprint/tests/test_filter_utils.cpp | 118 ++++ .../tests/test_fingerprint_calculator.cpp | 53 ++ .../tests/test_fingerprint_compressor.cpp | 79 +++ .../tests/test_fingerprint_decompressor.cpp | 77 +++ .../chromaprint/tests/test_integral_image.cpp | 40 ++ 3rdparty/chromaprint/tests/test_lloyds.cpp | 80 +++ 3rdparty/chromaprint/tests/test_quantizer.cpp | 17 + .../tests/test_silence_remover.cpp | 49 ++ 3rdparty/chromaprint/tests/test_utils.cpp | 91 ++++ 3rdparty/chromaprint/tests/test_utils.h | 42 ++ 3rdparty/chromaprint/tools/CMakeLists.txt | 63 +++ 3rdparty/chromaprint/tools/chromagram.cpp | 65 +++ 3rdparty/chromaprint/tools/decode.cpp | 28 + 3rdparty/chromaprint/tools/fillpuid.py | 76 +++ 3rdparty/chromaprint/tools/fpcollect.cpp | 323 +++++++++++ 3rdparty/chromaprint/tools/fpeval.cpp | 142 +++++ 3rdparty/chromaprint/tools/fpsubmit.py | 121 +++++ 3rdparty/chromaprint/tools/learn_filters.cpp | 396 ++++++++++++++ 3rdparty/chromaprint/tools/match.h | 42 ++ .../chromaprint/tools/misc/prepare-128mp3.sh | 13 + .../chromaprint/tools/misc/prepare-32mp3.sh | 13 + .../chromaprint/tools/misc/prepare-64mp3.sh | 13 + .../chromaprint/tools/misc/prepare-64wma.sh | 13 + .../chromaprint/tools/misc/prepare-gain.sh | 17 + .../tools/misc/prepare-resample.sh | 15 + .../chromaprint/tools/misc/prepare-wav.sh | 9 + 3rdparty/chromaprint/tools/misc/prepare.sh | 9 + 3rdparty/chromaprint/tools/resample.cpp | 35 ++ 3rdparty/chromaprint/tools/spectrogram.cpp | 63 +++ 135 files changed, 10664 insertions(+) create mode 100644 3rdparty/chromaprint/.gitignore create mode 100644 3rdparty/chromaprint/CHANGES.txt create mode 100644 3rdparty/chromaprint/CMakeLists.txt create mode 100644 3rdparty/chromaprint/COPYING.txt create mode 100644 3rdparty/chromaprint/NEWS.txt create mode 100644 3rdparty/chromaprint/README.txt create mode 100644 3rdparty/chromaprint/cmake/modules/FindFFTW3.cmake create mode 100644 3rdparty/chromaprint/cmake/modules/FindFFmpeg.cmake create mode 100644 3rdparty/chromaprint/cmake/modules/FindGTest.cmake create mode 100644 3rdparty/chromaprint/cmake/modules/FindTaglib.cmake create mode 100644 3rdparty/chromaprint/config.h.in create mode 100644 3rdparty/chromaprint/examples/CMakeLists.txt create mode 100644 3rdparty/chromaprint/examples/ffmpeg/audioconvert.h create mode 100644 3rdparty/chromaprint/examples/ffmpeg/samplefmt.h create mode 100644 3rdparty/chromaprint/examples/fpcalc.c create mode 100644 3rdparty/chromaprint/libchromaprint.pc.cmake create mode 100644 3rdparty/chromaprint/src/CMakeLists.txt create mode 100644 3rdparty/chromaprint/src/audio_consumer.h create mode 100644 3rdparty/chromaprint/src/audio_processor.cpp create mode 100644 3rdparty/chromaprint/src/audio_processor.h create mode 100644 3rdparty/chromaprint/src/avresample/avcodec.h create mode 100644 3rdparty/chromaprint/src/avresample/dsputil.h create mode 100644 3rdparty/chromaprint/src/avresample/resample2.c create mode 100644 3rdparty/chromaprint/src/base64.cpp create mode 100644 3rdparty/chromaprint/src/base64.h create mode 100644 3rdparty/chromaprint/src/bit_string_reader.h create mode 100644 3rdparty/chromaprint/src/bit_string_writer.h create mode 100644 3rdparty/chromaprint/src/chroma.cpp create mode 100644 3rdparty/chromaprint/src/chroma.h create mode 100644 3rdparty/chromaprint/src/chroma_filter.cpp create mode 100644 3rdparty/chromaprint/src/chroma_filter.h create mode 100644 3rdparty/chromaprint/src/chroma_normalizer.h create mode 100644 3rdparty/chromaprint/src/chroma_resampler.cpp create mode 100644 3rdparty/chromaprint/src/chroma_resampler.h create mode 100644 3rdparty/chromaprint/src/chromaprint.cpp create mode 100644 3rdparty/chromaprint/src/chromaprint.h create mode 100644 3rdparty/chromaprint/src/classifier.h create mode 100644 3rdparty/chromaprint/src/combined_buffer.h create mode 100644 3rdparty/chromaprint/src/debug.h create mode 100644 3rdparty/chromaprint/src/decoder.h create mode 100644 3rdparty/chromaprint/src/ext/audio_dumper.h create mode 100644 3rdparty/chromaprint/src/ext/ffmpeg_decoder.h create mode 100644 3rdparty/chromaprint/src/ext/image_utils.cpp create mode 100644 3rdparty/chromaprint/src/ext/image_utils.h create mode 100644 3rdparty/chromaprint/src/ext/sox_decoder.h create mode 100644 3rdparty/chromaprint/src/feature_vector_consumer.h create mode 100644 3rdparty/chromaprint/src/fft.cpp create mode 100644 3rdparty/chromaprint/src/fft.h create mode 100644 3rdparty/chromaprint/src/fft_frame.h create mode 100644 3rdparty/chromaprint/src/fft_frame_consumer.h create mode 100644 3rdparty/chromaprint/src/fft_lib.h create mode 100644 3rdparty/chromaprint/src/fft_lib_avfft.cpp create mode 100644 3rdparty/chromaprint/src/fft_lib_avfft.h create mode 100644 3rdparty/chromaprint/src/fft_lib_fftw3.cpp create mode 100644 3rdparty/chromaprint/src/fft_lib_fftw3.h create mode 100644 3rdparty/chromaprint/src/fft_lib_vdsp.cpp create mode 100644 3rdparty/chromaprint/src/fft_lib_vdsp.h create mode 100644 3rdparty/chromaprint/src/filter.cpp create mode 100644 3rdparty/chromaprint/src/filter.h create mode 100644 3rdparty/chromaprint/src/filter_utils.h create mode 100644 3rdparty/chromaprint/src/fingerprint_calculator.cpp create mode 100644 3rdparty/chromaprint/src/fingerprint_calculator.h create mode 100644 3rdparty/chromaprint/src/fingerprint_compressor.cpp create mode 100644 3rdparty/chromaprint/src/fingerprint_compressor.h create mode 100644 3rdparty/chromaprint/src/fingerprint_decompressor.cpp create mode 100644 3rdparty/chromaprint/src/fingerprint_decompressor.h create mode 100644 3rdparty/chromaprint/src/fingerprinter.cpp create mode 100644 3rdparty/chromaprint/src/fingerprinter.h create mode 100644 3rdparty/chromaprint/src/fingerprinter_configuration.cpp create mode 100644 3rdparty/chromaprint/src/fingerprinter_configuration.h create mode 100644 3rdparty/chromaprint/src/foo.cpp create mode 100644 3rdparty/chromaprint/src/image.h create mode 100644 3rdparty/chromaprint/src/image_builder.cpp create mode 100644 3rdparty/chromaprint/src/image_builder.h create mode 100644 3rdparty/chromaprint/src/integral_image.cpp create mode 100644 3rdparty/chromaprint/src/integral_image.h create mode 100644 3rdparty/chromaprint/src/lloyds.cpp create mode 100644 3rdparty/chromaprint/src/lloyds.h create mode 100644 3rdparty/chromaprint/src/quantizer.h create mode 100644 3rdparty/chromaprint/src/silence_remover.cpp create mode 100644 3rdparty/chromaprint/src/silence_remover.h create mode 100644 3rdparty/chromaprint/src/sox_audio_source.cpp create mode 100644 3rdparty/chromaprint/src/sox_audio_source.h create mode 100644 3rdparty/chromaprint/src/spectral_centroid.cpp create mode 100644 3rdparty/chromaprint/src/spectral_centroid.h create mode 100644 3rdparty/chromaprint/src/spectrum.cpp create mode 100644 3rdparty/chromaprint/src/spectrum.h create mode 100644 3rdparty/chromaprint/src/utils.h create mode 100644 3rdparty/chromaprint/tests/CMakeLists.txt create mode 100644 3rdparty/chromaprint/tests/audio_buffer.h create mode 100644 3rdparty/chromaprint/tests/data/test_mono_11025.raw create mode 100644 3rdparty/chromaprint/tests/data/test_mono_44100.raw create mode 100644 3rdparty/chromaprint/tests/data/test_mono_8000.raw create mode 100644 3rdparty/chromaprint/tests/data/test_stereo_44100.raw create mode 100644 3rdparty/chromaprint/tests/main.cpp create mode 100644 3rdparty/chromaprint/tests/test_api.cpp create mode 100644 3rdparty/chromaprint/tests/test_audio_processor.cpp create mode 100644 3rdparty/chromaprint/tests/test_base64.cpp create mode 100644 3rdparty/chromaprint/tests/test_bit_string_reader.cpp create mode 100644 3rdparty/chromaprint/tests/test_bit_string_writer.cpp create mode 100644 3rdparty/chromaprint/tests/test_chroma.cpp create mode 100644 3rdparty/chromaprint/tests/test_chroma_filter.cpp create mode 100644 3rdparty/chromaprint/tests/test_chroma_resampler.cpp create mode 100644 3rdparty/chromaprint/tests/test_chromaprint.cpp create mode 100644 3rdparty/chromaprint/tests/test_combined_buffer.cpp create mode 100644 3rdparty/chromaprint/tests/test_filter.cpp create mode 100644 3rdparty/chromaprint/tests/test_filter_utils.cpp create mode 100644 3rdparty/chromaprint/tests/test_fingerprint_calculator.cpp create mode 100644 3rdparty/chromaprint/tests/test_fingerprint_compressor.cpp create mode 100644 3rdparty/chromaprint/tests/test_fingerprint_decompressor.cpp create mode 100644 3rdparty/chromaprint/tests/test_integral_image.cpp create mode 100644 3rdparty/chromaprint/tests/test_lloyds.cpp create mode 100644 3rdparty/chromaprint/tests/test_quantizer.cpp create mode 100644 3rdparty/chromaprint/tests/test_silence_remover.cpp create mode 100644 3rdparty/chromaprint/tests/test_utils.cpp create mode 100644 3rdparty/chromaprint/tests/test_utils.h create mode 100644 3rdparty/chromaprint/tools/CMakeLists.txt create mode 100644 3rdparty/chromaprint/tools/chromagram.cpp create mode 100644 3rdparty/chromaprint/tools/decode.cpp create mode 100755 3rdparty/chromaprint/tools/fillpuid.py create mode 100644 3rdparty/chromaprint/tools/fpcollect.cpp create mode 100644 3rdparty/chromaprint/tools/fpeval.cpp create mode 100755 3rdparty/chromaprint/tools/fpsubmit.py create mode 100644 3rdparty/chromaprint/tools/learn_filters.cpp create mode 100644 3rdparty/chromaprint/tools/match.h create mode 100755 3rdparty/chromaprint/tools/misc/prepare-128mp3.sh create mode 100755 3rdparty/chromaprint/tools/misc/prepare-32mp3.sh create mode 100755 3rdparty/chromaprint/tools/misc/prepare-64mp3.sh create mode 100755 3rdparty/chromaprint/tools/misc/prepare-64wma.sh create mode 100755 3rdparty/chromaprint/tools/misc/prepare-gain.sh create mode 100755 3rdparty/chromaprint/tools/misc/prepare-resample.sh create mode 100755 3rdparty/chromaprint/tools/misc/prepare-wav.sh create mode 100755 3rdparty/chromaprint/tools/misc/prepare.sh create mode 100644 3rdparty/chromaprint/tools/resample.cpp create mode 100644 3rdparty/chromaprint/tools/spectrogram.cpp diff --git a/3rdparty/chromaprint/.gitignore b/3rdparty/chromaprint/.gitignore new file mode 100644 index 000000000..f9889eb31 --- /dev/null +++ b/3rdparty/chromaprint/.gitignore @@ -0,0 +1,38 @@ +CMakeFiles +CMakeCache.txt +Makefile +cmake_install.cmake +config.h +tests/all_tests +tools/fpgen +tools/fpcollect +*.exe +*.dll +*.so +*.a +tools/fpeval +tools/learn_filters +tools/decode +tools/chromagram +tools/resample +libchromaprint.pc +install_manifest.txt +tools/spectrogram +src/libchromaprint.so.* +*.vcxproj +*.vcxproj.* +*.dir +*.sln +*.suo +Debug +src/Debug +*.dll +*.lib +*.pdb +*.dll.manifest +*.exp +*.dylib +*.vcproj +*.user +*.ncb +src/Release diff --git a/3rdparty/chromaprint/CHANGES.txt b/3rdparty/chromaprint/CHANGES.txt new file mode 100644 index 000000000..6977b6aee --- /dev/null +++ b/3rdparty/chromaprint/CHANGES.txt @@ -0,0 +1,5 @@ +Version 0.1 (2010-10-30) +======================== + +- Initial release. + diff --git a/3rdparty/chromaprint/CMakeLists.txt b/3rdparty/chromaprint/CMakeLists.txt new file mode 100644 index 000000000..ddcf7afaa --- /dev/null +++ b/3rdparty/chromaprint/CMakeLists.txt @@ -0,0 +1,158 @@ +cmake_minimum_required(VERSION 2.6) + +project(chromaprint) +set(PROJECT_VERSION 0.6.0) + +# 1. If the library source code has changed at all since the last update, then increment revision. +# 2. If any interfaces have been added, removed, or changed since the last update, increment current, and set revision to 0. +# 3. If any interfaces have been added since the last public release, then increment age. +# 4. If any interfaces have been removed since the last public release, then set age to 0. +set(chromaprint_SOVERSION_CURRENT 1) +set(chromaprint_SOVERSION_REVISION 4) +set(chromaprint_SOVERSION_AGE 1) + +math(EXPR chromaprint_SOVERSION_MAJOR "${chromaprint_SOVERSION_CURRENT} - ${chromaprint_SOVERSION_AGE}") +math(EXPR chromaprint_SOVERSION_MINOR "${chromaprint_SOVERSION_AGE}") +math(EXPR chromaprint_SOVERSION_PATCH "${chromaprint_SOVERSION_REVISION}") + +set(chromaprint_VERSION ${chromaprint_SOVERSION_MAJOR}.${chromaprint_SOVERSION_MINOR}.${chromaprint_SOVERSION_PATCH}) +set(chromaprint_SOVERSION ${chromaprint_SOVERSION_MAJOR}) + +include(CheckFunctionExists) +set(CMAKE_REQUIRED_LIBRARIES -lm) +check_function_exists(lrintf HAVE_LRINTF) +check_function_exists(round HAVE_ROUND) + +add_definitions( + -DHAVE_CONFIG_H + -D_SCL_SECURE_NO_WARNINGS + -D_USE_MATH_DEFINES + -D__STDC_LIMIT_MACROS + -D__STDC_CONSTANT_MACROS +) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)") +set(EXEC_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} CACHE PATH "Installation prefix for executables and object code libraries" FORCE) +set(BIN_INSTALL_DIR ${EXEC_INSTALL_PREFIX}/bin CACHE PATH "Installation prefix for user executables" FORCE) +set(LIB_INSTALL_DIR ${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX} CACHE PATH "Installation prefix for object code libraries" FORCE) +set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include CACHE PATH "Installation prefix for C header files" FORCE) + +if(APPLE) + option(BUILD_FRAMEWORK "Build an OS X framework" OFF) + set(FRAMEWORK_INSTALL_DIR "/Library/Frameworks" CACHE STRING "Directory to install frameworks to.") +endif() + +option(BUILD_SHARED_LIBS "Build shared libraries" OFF) +option(BUILD_EXAMPLES "Build the examples" OFF) +option(BUILD_TESTS "Build the test suite" OFF) +option(BUILD_TOOLS "Build standard tools" OFF) +option(BUILD_EXTRA_TOOLS "Build extra tools (only useful for development of this library)" OFF) + +if(CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") +endif() +if(CMAKE_COMPILER_IS_GNUCXX AND BUILD_SHARED_LIBS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") +endif() + +if(NOT BUILD_SHARED_LIBS) + add_definitions(-DCHROMAPRINT_NODLL) +endif() + +option(WITH_AVFFT "Use FFmpeg for FFT calculations" OFF) +option(WITH_FFTW3 "Use FFTW3 for FFT calculations" OFF) +option(WITH_VDSP "Use vDSP for FFT calculations" OFF) + +set(TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tests/) + +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) +find_package(FFmpeg) +find_package(FFTW3) +if(APPLE) + find_library(ACCELERATE_LIBRARIES Accelerate) +endif() + +set(FFT_OPTION_COUNT 0) + +if(WITH_AVFFT) + math(EXPR FFT_OPTION_COUNT "${FFT_OPTION_COUNT} + 1") +endif() +if(WITH_FFTW3) + math(EXPR FFT_OPTION_COUNT "${FFT_OPTION_COUNT} + 1") +endif() +if(WITH_VDSP) + math(EXPR FFT_OPTION_COUNT "${FFT_OPTION_COUNT} + 1") +endif() +if(FFT_OPTION_COUNT GREATER "1") + message(FATAL_ERROR "Only one of WITH_AVFFT, WITH_FFTW3 AND WITH_VDSP can be selected") +endif() + +if(WITH_AVFFT AND NOT FFMPEG_LIBAVCODEC_FFT_FOUND) + message(FATAL_ERROR "FFmpeg with avfft.h not found") +endif() + +if(WITH_FFTW3 AND NOT FFTW3_FOUND) + message(FATAL_ERROR "FFTW3 not found") +endif() + +if(APPLE AND WITH_VDSP AND NOT ACCELERATE_LIBRARIES) + message(FATAL_ERROR "vDSP (Accelerate) not found") +endif() + +if(NOT WITH_AVFFT AND NOT WITH_FFTW3) + if(APPLE AND ACCELERATE_LIBRARIES) + set(WITH_VDSP ON) + elseif(FFMPEG_LIBAVCODEC_FFT_FOUND) + set(WITH_AVFFT ON) + elseif(FFTW3_FOUND) + set(WITH_FFTW3 ON) + else() + message(FATAL_ERROR "Neither FFmpeg with avfft.h nor FFTW3 found") + endif() +endif() + +if(WITH_AVFFT) + message(STATUS "Using FFmpeg for FFT calculations") +endif(WITH_AVFFT) + +if(WITH_FFTW3) + message(STATUS "Using FFTW3 for FFT calculations") +endif(WITH_FFTW3) + +if(NOT APPLE AND NOT BUILD_FRAMEWORK) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libchromaprint.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libchromaprint.pc) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libchromaprint.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) +endif() + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) + +add_subdirectory(src) + +if(BUILD_TOOLS_EXTRA) + find_package(PNG REQUIRED) +endif(BUILD_TOOLS_EXTRA) + +find_package(Boost COMPONENTS system filesystem) +if(BUILD_TOOLS OR BUILD_TOOLS_EXTRA OR BUILD_EXAMPLES) + find_package(FFmpeg REQUIRED) +endif() + +if(BUILD_EXAMPLES) + add_subdirectory(examples) +endif() + +if(BUILD_TOOLS OR BUILD_TOOLS_EXTRA) + find_package(Taglib REQUIRED) + add_subdirectory(tools) +endif(BUILD_TOOLS OR BUILD_TOOLS_EXTRA) + +if(BUILD_TESTS) + find_package(Threads) + find_package(GTest REQUIRED) + add_subdirectory(tests) +endif(BUILD_TESTS) + diff --git a/3rdparty/chromaprint/COPYING.txt b/3rdparty/chromaprint/COPYING.txt new file mode 100644 index 000000000..4362b4915 --- /dev/null +++ b/3rdparty/chromaprint/COPYING.txt @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/3rdparty/chromaprint/NEWS.txt b/3rdparty/chromaprint/NEWS.txt new file mode 100644 index 000000000..96a12b671 --- /dev/null +++ b/3rdparty/chromaprint/NEWS.txt @@ -0,0 +1,44 @@ +Version 0.6 -- December 22, 2011 +================================ + + - Support for 24-bit file formats in fpcalc. + - The fpcalc utility now uses 120 seconds of audio data by default. + - Python bindings moved to a separate project (pyacoustid). + +Version 0.5 -- October 6, 2011 +============================== + + - Unicode command line handling in fpcalc. + - Fixed a crash in fpcalc when FFmpeg was not able to identify the codec. + - Added encode_fingerprint to the Python bindings. + +Version 0.4 -- May 14, 2011 +=========================== + + - Support for building a Mac OS X framework. + - Support for building a static library. + - Simple C example (fpcalc) that can be used from external applications for + fingerprint calculations. + +Version 0.3 -- April 26, 2011 +============================= + + - Fixed compilation with MSVC 2010. + - Added support for calculating FFT using the Accelerate framework on + Mac OS X and iOS. + - Added Python bindings. + +Version 0.2 -- January 26, 2011 +=============================== + + - New public functions chromaprint_{encode,decode}_fingerprint to + encoding/decoding raw fingerprints. + - New public function chromaprint_dealloc that should be used for + releasing all memory allocated in Chromaprint functions. + - Extended fpcollect to allow processing files with MBIDs. + +Version 0.1 -- October 30, 2010 +=============================== + + - Initial release + diff --git a/3rdparty/chromaprint/README.txt b/3rdparty/chromaprint/README.txt new file mode 100644 index 000000000..aeac70c15 --- /dev/null +++ b/3rdparty/chromaprint/README.txt @@ -0,0 +1,96 @@ +Chromaprint +=========== + +Dependencies +------------ + +The library itself only depends on a FFT library, which at the moment can +be either FFmpeg [1] (at least r22291, 0.6 is fine), FFTW3 [2] or if you are +on iOS or OS X, you can use the Accelerate/vDSP framework. See the next +section for details. + +The tools included in the package require FFmpeg (can be older), TagLib [3] +and Boost Filesystem [4]. + +In order to build the test suite, you will need the Google Test library [5]. + +[1] http://www.ffmpeg.org/ +[2] http://www.fftw.org/ +[3] http://developer.kde.org/~wheeler/taglib.html +[4] http://www.boost.org/ +[5] http://code.google.com/p/googletest/ + +Installing +---------- + +The most common way to build Chromaprint is like this: + +$ cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLES=ON . +$ make +$ sudo make install + +This will build Chromaprint as a shared library and also include the fpcalc +utility (which is used by MusicBrainz Picard, for example). + +See below for other options. + +FFT Library +----------- + +Chromaprint can use three FFT libraries, FFmpeg, FFTW3 and vDSP. FFmpeg is +preffered, as it's a little faster for our purposes and it's LGPL-licensed, +so it doesn't impact the license of Chromaprint. The FFT interface was added +only recently though, so it might not be available in Linux distributions yet. +FFTW3 can be used in this case, but this library is released under the GPL +license, which makes also the resulting Chromaprint binary GPL licensed. + +If you run simple `cmake .`, it will try to find both FFmpeg and FFTW3 and +select the first one it finds. If you have new FFmpeg installed in a separate +location, you can let CMake know using the `FFMPEG_ROOT` option: + +$ cmake -DFFMPEG_ROOT=/path/to/local/ffmpeg/install . + +If you have new FFmpeg installed, but for some reason prefer to use FFTW3, you +can use the `WITH_FFTW3` option: + +$ cmake -DWITH_FFTW3=ON . + +There is also a `WITH_AVFFT` option, but the script will select the FFmpeg FFT +automatically if it's available, so it shouldn't be necessary to use it. + +If you are on Mac, you can use the standard Accelerate framework with the vDSP +library. This requires you to install no external libraries. It will use +vDSP by default on OS X (but there still is a `WITH_VDSP` option). + +Unit Tests +---------- + +The test suite can be built and run using the following commands: + +$ cmake -DBUILD_TESTS=ON . +$ make check + +Related Projects +---------------- + + * pyacoustid - https://github.com/sampsyo/pyacoustid + * gst-chromaprint - https://github.com/lalinsky/gst-chromaprint + +Standing on the Shoulder of Giants +---------------------------------- + +I've learned a lot while working on this project, which would not be possible +without having information from past research. I've read many papers, but the +concrete ideas implemented in this library are based on the following papers: + + * Yan Ke, Derek Hoiem, Rahul Sukthankar. Computer Vision for Music + Identification, Proceedings of Computer Vision and Pattern Recognition, + 2005. http://www.cs.cmu.edu/~yke/musicretrieval/ + + * Frank Kurth, Meinard Müller. Efficient Index-Based Audio Matching, 2008. + http://dx.doi.org/10.1109/TASL.2007.911552 + + * Dalwon Jang, Chang D. Yoo, Sunil Lee, Sungwoong Kim, Ton Kalker. + Pairwise Boosted Audio Fingerprint, 2009. + http://dx.doi.org/10.1109/TIFS.2009.2034452 + diff --git a/3rdparty/chromaprint/cmake/modules/FindFFTW3.cmake b/3rdparty/chromaprint/cmake/modules/FindFFTW3.cmake new file mode 100644 index 000000000..fb5cef88d --- /dev/null +++ b/3rdparty/chromaprint/cmake/modules/FindFFTW3.cmake @@ -0,0 +1,133 @@ +# +# Try to find FFTW3 library +# (see www.fftw.org) +# Once run this will define: +# +# FFTW3_FOUND +# FFTW3_INCLUDE_DIR +# FFTW3_LIBRARIES +# FFTW3_LINK_DIRECTORIES +# +# You may set one of these options before including this file: +# FFTW3_USE_SSE2 +# +# TODO: _F_ versions. +# +# Jan Woetzel 05/2004 +# www.mip.informatik.uni-kiel.de +# -------------------------------- + + FIND_PATH(FFTW3_INCLUDE_DIR fftw3.h + ${FFTW3_DIR}/include + ${FFTW3_HOME}/include + ${FFTW3_DIR} + ${FFTW3_HOME} + $ENV{FFTW3_DIR}/include + $ENV{FFTW3_HOME}/include + $ENV{FFTW3_DIR} + $ENV{FFTW3_HOME} + /usr/include + /usr/local/include + $ENV{SOURCE_DIR}/fftw3 + $ENV{SOURCE_DIR}/fftw3/include + $ENV{SOURCE_DIR}/fftw + $ENV{SOURCE_DIR}/fftw/include + ) +#MESSAGE("DBG FFTW3_INCLUDE_DIR=${FFTW3_INCLUDE_DIR}") + + +SET(FFTW3_POSSIBLE_LIBRARY_PATH + ${FFTW3_DIR}/lib + ${FFTW3_HOME}/lib + ${FFTW3_DIR} + ${FFTW3_HOME} + $ENV{FFTW3_DIR}/lib + $ENV{FFTW3_HOME}/lib + $ENV{FFTW3_DIR} + $ENV{FFTW3_HOME} + /usr/lib + /usr/local/lib + $ENV{SOURCE_DIR}/fftw3 + $ENV{SOURCE_DIR}/fftw3/lib + $ENV{SOURCE_DIR}/fftw + $ENV{SOURCE_DIR}/fftw/lib +) + + +# the lib prefix is containe din filename onf W32, unfortuantely. JW +# teh "general" lib: +FIND_LIBRARY(FFTW3_FFTW_LIBRARY + NAMES fftw3 libfftw libfftw3 libfftw3-3 + PATHS + ${FFTW3_POSSIBLE_LIBRARY_PATH} + ) +#MESSAGE("DBG FFTW3_FFTW_LIBRARY=${FFTW3_FFTW_LIBRARY}") + +FIND_LIBRARY(FFTW3_FFTWF_LIBRARY + NAMES fftwf3 fftwf libfftwf libfftwf3 libfftw3f-3 + PATHS + ${FFTW3_POSSIBLE_LIBRARY_PATH} + ) +#MESSAGE("DBG FFTW3_FFTWF_LIBRARY=${FFTW3_FFTWF_LIBRARY}") + +FIND_LIBRARY(FFTW3_FFTWL_LIBRARY + NAMES fftwl3 fftwl libfftwl libfftwl3 libfftw3l-3 + PATHS + ${FFTW3_POSSIBLE_LIBRARY_PATH} + ) +#MESSAGE("DBG FFTW3_FFTWF_LIBRARY=${FFTW3_FFTWL_LIBRARY}") + + +FIND_LIBRARY(FFTW3_FFTW_SSE2_LIBRARY + NAMES fftw_sse2 fftw3_sse2 libfftw_sse2 libfftw3_sse2 + PATHS + ${FFTW3_POSSIBLE_LIBRARY_PATH} + ) +#MESSAGE("DBG FFTW3_FFTW_SSE2_LIBRARY=${FFTW3_FFTW_SSE2_LIBRARY}") + +FIND_LIBRARY(FFTW3_FFTWF_SSE_LIBRARY + NAMES fftwf_sse fftwf3_sse libfftwf_sse libfftwf3_sse + PATHS + ${FFTW3_POSSIBLE_LIBRARY_PATH} + ) +#MESSAGE("DBG FFTW3_FFTWF_SSE_LIBRARY=${FFTW3_FFTWF_SSE_LIBRARY}") + + +# -------------------------------- +# select one of the above +# default: +IF (FFTW3_FFTW_LIBRARY) + SET(FFTW3_LIBRARIES ${FFTW3_FFTW_LIBRARY}) +ENDIF (FFTW3_FFTW_LIBRARY) +# specialized: +IF (FFTW3_USE_SSE2 AND FFTW3_FFTW_SSE2_LIBRARY) + SET(FFTW3_LIBRARIES ${FFTW3_FFTW_SSE2_LIBRARY}) +ENDIF (FFTW3_USE_SSE2 AND FFTW3_FFTW_SSE2_LIBRARY) + +# -------------------------------- + +IF(FFTW3_LIBRARIES) + IF (FFTW3_INCLUDE_DIR) + + # OK, found all we need + SET(FFTW3_FOUND TRUE) + GET_FILENAME_COMPONENT(FFTW3_LINK_DIRECTORIES ${FFTW3_LIBRARIES} PATH) + + ELSE (FFTW3_INCLUDE_DIR) + MESSAGE("FFTW3 include dir not found. Set FFTW3_DIR to find it.") + ENDIF(FFTW3_INCLUDE_DIR) +ELSE(FFTW3_LIBRARIES) + MESSAGE("FFTW3 lib not found. Set FFTW3_DIR to find it.") +ENDIF(FFTW3_LIBRARIES) + + +MARK_AS_ADVANCED( + FFTW3_INCLUDE_DIR + FFTW3_LIBRARIES + FFTW3_FFTW_LIBRARY + FFTW3_FFTW_SSE2_LIBRARY + FFTW3_FFTWF_LIBRARY + FFTW3_FFTWF_SSE_LIBRARY + FFTW3_FFTWL_LIBRARY + FFTW3_LINK_DIRECTORIES +) diff --git a/3rdparty/chromaprint/cmake/modules/FindFFmpeg.cmake b/3rdparty/chromaprint/cmake/modules/FindFFmpeg.cmake new file mode 100644 index 000000000..d29ec802b --- /dev/null +++ b/3rdparty/chromaprint/cmake/modules/FindFFmpeg.cmake @@ -0,0 +1,128 @@ +# Locate ffmpeg +# This module defines +# FFMPEG_LIBRARIES +# FFMPEG_FOUND, if false, do not try to link to ffmpeg +# FFMPEG_INCLUDE_DIR, where to find the headers +# +# $FFMPEG_DIR is an environment variable that would +# correspond to the ./configure --prefix=$FFMPEG_DIR +# +# Created by Robert Osfield. +# Modified by Lukas Lalinsky. + + +#In ffmpeg code, old version use "#include " and newer use "#include " +#In OSG ffmpeg plugin, we use "#include " for compatibility with old version of ffmpeg + +#We have to search the path which contain the header.h (usefull for old version) +#and search the path which contain the libname/header.h (usefull for new version) + +#Then we need to include ${FFMPEG_libname_INCLUDE_DIRS} (in old version case, use by ffmpeg header and osg plugin code) +# (in new version case, use by ffmpeg header) +#and ${FFMPEG_libname_INCLUDE_DIRS/libname} (in new version case, use by osg plugin code) + +# Macro to find header and lib directories +# example: FFMPEG_FIND(AVFORMAT avformat avformat.h) +MACRO(FFMPEG_FIND varname shortname headername) + + FIND_PATH(FFMPEG_${varname}_INCLUDE_DIRS lib${shortname}/${headername} + PATHS + ${FFMPEG_ROOT}/include + $ENV{FFMPEG_DIR}/include + ~/Library/Frameworks + /Library/Frameworks + /usr/local/include + /usr/include/ + /sw/include # Fink + /opt/local/include # DarwinPorts + /opt/csw/include # Blastwave + /opt/include + /usr/freeware/include + NO_DEFAULT_PATH + PATH_SUFFIXES ffmpeg + DOC "Location of FFMPEG Headers" + ) + FIND_PATH(FFMPEG_${varname}_INCLUDE_DIRS lib${shortname}/${headername} + PATH_SUFFIXES ffmpeg + DOC "Location of FFMPEG Headers" + ) + + FIND_LIBRARY(FFMPEG_${varname}_LIBRARIES + NAMES ${shortname} + PATHS + ${FFMPEG_ROOT}/lib + $ENV{FFMPEG_DIR}/lib + ~/Library/Frameworks + /Library/Frameworks + /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 + /sw/lib + /opt/local/lib + /opt/csw/lib + /opt/lib + /usr/freeware/lib64 + NO_DEFAULT_PATH + DOC "Location of FFMPEG Libraries" + ) + FIND_LIBRARY(FFMPEG_${varname}_LIBRARIES + NAMES ${shortname} + DOC "Location of FFMPEG Libraries" + ) + + IF (FFMPEG_${varname}_LIBRARIES AND FFMPEG_${varname}_INCLUDE_DIRS) + SET(FFMPEG_${varname}_FOUND 1) + ENDIF(FFMPEG_${varname}_LIBRARIES AND FFMPEG_${varname}_INCLUDE_DIRS) + +ENDMACRO(FFMPEG_FIND) + +SET(FFMPEG_ROOT "$ENV{FFMPEG_DIR}" CACHE PATH "Location of FFMPEG") + +# find stdint.h +FIND_PATH(FFMPEG_STDINT_INCLUDE_DIR stdint.h + PATHS + ${FFMPEG_ROOT}/include + $ENV{FFMPEG_DIR}/include + ~/Library/Frameworks + /Library/Frameworks + /usr/local/include + /usr/include + /sw/include # Fink + /opt/local/include # DarwinPorts + /opt/csw/include # Blastwave + /opt/include + /usr/freeware/include + PATH_SUFFIXES ffmpeg + DOC "Location of FFMPEG stdint.h Header" +) + +FFMPEG_FIND(LIBAVFORMAT avformat avformat.h) +FFMPEG_FIND(LIBAVDEVICE avdevice avdevice.h) +FFMPEG_FIND(LIBAVCODEC avcodec avcodec.h) +FFMPEG_FIND(LIBAVCODEC_FFT avcodec avfft.h) +FFMPEG_FIND(LIBAVUTIL avutil avutil.h) +FFMPEG_FIND(LIBSWSCALE swscale swscale.h) # not sure about the header to look for here. + +SET(FFMPEG_FOUND "NO") +# Note we don't check FFMPEG_LIBSWSCALE_FOUND here, it's optional. +IF (FFMPEG_LIBAVFORMAT_FOUND AND FFMPEG_LIBAVDEVICE_FOUND AND FFMPEG_LIBAVCODEC_FOUND AND FFMPEG_LIBAVUTIL_FOUND AND FFMPEG_STDINT_INCLUDE_DIR) + + SET(FFMPEG_FOUND "YES") + + SET(FFMPEG_INCLUDE_DIRS ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS}) + + SET(FFMPEG_LIBRARY_DIRS ${FFMPEG_LIBAVFORMAT_LIBRARY_DIRS}) + + # Note we don't add FFMPEG_LIBSWSCALE_LIBRARIES here, it will be added if found later. + SET(FFMPEG_LIBRARIES + ${FFMPEG_LIBAVFORMAT_LIBRARIES} + ${FFMPEG_LIBAVDEVICE_LIBRARIES} + ${FFMPEG_LIBAVCODEC_LIBRARIES} + ${FFMPEG_LIBAVUTIL_LIBRARIES}) + +ELSE () + +# MESSAGE(STATUS "Could not find FFMPEG") + +ENDIF() diff --git a/3rdparty/chromaprint/cmake/modules/FindGTest.cmake b/3rdparty/chromaprint/cmake/modules/FindGTest.cmake new file mode 100644 index 000000000..367ffae66 --- /dev/null +++ b/3rdparty/chromaprint/cmake/modules/FindGTest.cmake @@ -0,0 +1,175 @@ +# Locate the Google C++ Testing Framework. +# +# Defines the following variables: +# +# GTEST_FOUND - Found the Google Testing framework +# GTEST_INCLUDE_DIRS - Include directories +# +# Also defines the library variables below as normal +# variables. These contain debug/optimized keywords when +# a debugging library is found. +# +# GTEST_BOTH_LIBRARIES - Both libgtest & libgtest-main +# GTEST_LIBRARIES - libgtest +# GTEST_MAIN_LIBRARIES - libgtest-main +# +# Accepts the following variables as input: +# +# GTEST_ROOT - (as CMake or env. variable) +# The root directory of the gtest install prefix +# +# GTEST_MSVC_SEARCH - If on MSVC, enables searching the build tree of +# GTest if set to MD or MT (defaults: MD) +# +#----------------------- +# Example Usage: +# +# enable_testing(true) +# find_package(GTest REQUIRED) +# include_directories(${GTEST_INCLUDE_DIRS}) +# +# add_executable(foo foo.cc) +# target_link_libraries(foo ${GTEST_BOTH_LIBRARIES}) +# +# add_test(AllTestsInFoo foo) +# +#----------------------- +# +# If you would like each Google test to show up in CTest as +# a test you may use the following macro. NOTE: It WILL slow +# down your tests, so be warned. +# +# GTEST_ADD_TESTS(executable extra_args ARGN) +# executable = The path to the test executable +# extra_args = Pass a list of extra arguments to be passed to +# executable enclosed in quotes (or "" for none) +# ARGN = A list of source files to search for tests & test +# fixtures. +# +# Example: +# set(FooTestArgs --foo 1 --bar 2) +# add_executable(FooTest FooUnitTest.cc) +# GTEST_ADD_TESTS(FooTest "${FooTestArgs}" FooUnitTest.cc) + +#============================================================================= +# Copyright 2009 Kitware, Inc. +# Copyright 2009 Philip Lowman +# Copyright 2009 Daniel Blezek +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +#============================================================================= +# +# Thanks to Daniel Blezek for the GTEST_ADD_TESTS code + +function(GTEST_ADD_TESTS executable extra_args) + if(NOT ARGN) + message(FATAL_ERROR "Missing ARGN: Read the documentation for GTEST_ADD_TESTS") + endif() + foreach(source ${ARGN}) + file(READ "${source}" contents) + string(REGEX MATCHALL "TEST_?F?\\(([A-Za-z_0-9 ,]+)\\)" found_tests ${contents}) + foreach(hit ${found_tests}) + string(REGEX REPLACE ".*\\(([A-Za-z_0-9]+)[, ]*([A-Za-z_0-9]+)\\).*" "\\1.\\2" test_name ${hit}) + add_test(${test_name} ${executable} --gtest_filter=${test_name} ${extra_args}) + endforeach() + endforeach() +endfunction() + +function(_gtest_append_debugs _endvar _library) + if(${_library} AND ${_library}_DEBUG) + set(_output optimized ${${_library}} debug ${${_library}_DEBUG}) + else() + set(_output ${${_library}}) + endif() + set(${_endvar} ${_output} PARENT_SCOPE) +endfunction() + +function(_gtest_find_library _name) + find_library(${_name} + NAMES ${ARGN} + HINTS + $ENV{GTEST_ROOT} + ${GTEST_ROOT} + PATH_SUFFIXES ${_gtest_libpath_suffixes} + ) + mark_as_advanced(${_name}) +endfunction() + +# + +if(NOT DEFINED GTEST_MSVC_SEARCH) + set(GTEST_MSVC_SEARCH MD) +endif() + +set(_gtest_libpath_suffixes lib) +if(MSVC) + if(GTEST_MSVC_SEARCH STREQUAL "MD") + list(APPEND _gtest_libpath_suffixes + msvc/gtest-md/Debug + msvc/gtest-md/Release) + elseif(GTEST_MSVC_SEARCH STREQUAL "MT") + list(APPEND _gtest_libpath_suffixes + msvc/gtest/Debug + msvc/gtest/Release) + endif() +endif() + + +find_path(GTEST_INCLUDE_DIR gtest/gtest.h + HINTS + $ENV{GTEST_ROOT}/include + ${GTEST_ROOT}/include +) +mark_as_advanced(GTEST_INCLUDE_DIR) + +if(MSVC AND GTEST_MSVC_SEARCH STREQUAL "MD") + # The provided /MD project files for Google Test add -md suffixes to the + # library names. + _gtest_find_library(GTEST_LIBRARY gtest-md gtest) + _gtest_find_library(GTEST_LIBRARY_DEBUG gtest-mdd gtestd) + _gtest_find_library(GTEST_MAIN_LIBRARY gtest_main-md gtest_main) + _gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_main-mdd gtest_maind) +else() + _gtest_find_library(GTEST_LIBRARY gtest) + _gtest_find_library(GTEST_LIBRARY_DEBUG gtestd) + _gtest_find_library(GTEST_MAIN_LIBRARY gtest_main) + _gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_maind) +endif() + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTest DEFAULT_MSG GTEST_LIBRARY GTEST_INCLUDE_DIR GTEST_MAIN_LIBRARY) + +if(GTEST_FOUND) + set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIR}) + _gtest_append_debugs(GTEST_LIBRARIES GTEST_LIBRARY) + _gtest_append_debugs(GTEST_MAIN_LIBRARIES GTEST_MAIN_LIBRARY) + set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES}) +endif() + diff --git a/3rdparty/chromaprint/cmake/modules/FindTaglib.cmake b/3rdparty/chromaprint/cmake/modules/FindTaglib.cmake new file mode 100644 index 000000000..76b83ac55 --- /dev/null +++ b/3rdparty/chromaprint/cmake/modules/FindTaglib.cmake @@ -0,0 +1,135 @@ +# - Try to find the Taglib library +# Once done this will define +# +# TAGLIB_FOUND - system has the taglib library +# TAGLIB_CFLAGS - the taglib cflags +# TAGLIB_LIBRARIES - The libraries needed to use taglib + +# Copyright (c) 2006, Laurent Montel, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +if(NOT TAGLIB_MIN_VERSION) + set(TAGLIB_MIN_VERSION "1.6") +endif(NOT TAGLIB_MIN_VERSION) + +if(NOT WIN32) + find_program(TAGLIBCONFIG_EXECUTABLE NAMES taglib-config PATHS + ${BIN_INSTALL_DIR} + ) +endif(NOT WIN32) + +#reset vars +set(TAGLIB_LIBRARIES) +set(TAGLIB_CFLAGS) + +# if taglib-config has been found +if(TAGLIBCONFIG_EXECUTABLE) + + exec_program(${TAGLIBCONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE TAGLIB_VERSION) + + if(TAGLIB_VERSION STRLESS "${TAGLIB_MIN_VERSION}") + message(STATUS "TagLib version too old: version searched :${TAGLIB_MIN_VERSION}, found ${TAGLIB_VERSION}") + set(TAGLIB_FOUND FALSE) + else(TAGLIB_VERSION STRLESS "${TAGLIB_MIN_VERSION}") + + exec_program(${TAGLIBCONFIG_EXECUTABLE} ARGS --libs RETURN_VALUE _return_VALUE OUTPUT_VARIABLE TAGLIB_LIBRARIES) + + exec_program(${TAGLIBCONFIG_EXECUTABLE} ARGS --cflags RETURN_VALUE _return_VALUE OUTPUT_VARIABLE TAGLIB_CFLAGS) + + if(TAGLIB_LIBRARIES AND TAGLIB_CFLAGS) + set(TAGLIB_FOUND TRUE) + endif(TAGLIB_LIBRARIES AND TAGLIB_CFLAGS) + string(REGEX REPLACE " *-I" ";" TAGLIB_INCLUDES "${TAGLIB_CFLAGS}") + endif(TAGLIB_VERSION STRLESS "${TAGLIB_MIN_VERSION}") + mark_as_advanced(TAGLIB_CFLAGS TAGLIB_LIBRARIES TAGLIB_INCLUDES) + +else(TAGLIBCONFIG_EXECUTABLE) + + find_path(TAGLIB_INCLUDES + NAMES + tag.h + PATH_SUFFIXES taglib + PATHS + ${KDE4_INCLUDE_DIR} + ${INCLUDE_INSTALL_DIR} + ) + + IF(NOT WIN32) + # on non-win32 we don't need to take care about WIN32_DEBUG_POSTFIX + + FIND_LIBRARY(TAGLIB_LIBRARIES tag PATHS ${KDE4_LIB_DIR} ${LIB_INSTALL_DIR}) + + ELSE(NOT WIN32) + + # 1. get all possible libnames + SET(args PATHS ${KDE4_LIB_DIR} ${LIB_INSTALL_DIR}) + SET(newargs "") + SET(libnames_release "") + SET(libnames_debug "") + + LIST(LENGTH args listCount) + + # just one name + LIST(APPEND libnames_release "tag") + LIST(APPEND libnames_debug "tagd") + + SET(newargs ${args}) + + # search the release lib + FIND_LIBRARY(TAGLIB_LIBRARIES_RELEASE + NAMES ${libnames_release} + ${newargs} + ) + + # search the debug lib + FIND_LIBRARY(TAGLIB_LIBRARIES_DEBUG + NAMES ${libnames_debug} + ${newargs} + ) + + IF(TAGLIB_LIBRARIES_RELEASE AND TAGLIB_LIBRARIES_DEBUG) + + # both libs found + SET(TAGLIB_LIBRARIES optimized ${TAGLIB_LIBRARIES_RELEASE} + debug ${TAGLIB_LIBRARIES_DEBUG}) + + ELSE(TAGLIB_LIBRARIES_RELEASE AND TAGLIB_LIBRARIES_DEBUG) + + IF(TAGLIB_LIBRARIES_RELEASE) + + # only release found + SET(TAGLIB_LIBRARIES ${TAGLIB_LIBRARIES_RELEASE}) + + ELSE(TAGLIB_LIBRARIES_RELEASE) + + # only debug (or nothing) found + SET(TAGLIB_LIBRARIES ${TAGLIB_LIBRARIES_DEBUG}) + + ENDIF(TAGLIB_LIBRARIES_RELEASE) + + ENDIF(TAGLIB_LIBRARIES_RELEASE AND TAGLIB_LIBRARIES_DEBUG) + + MARK_AS_ADVANCED(TAGLIB_LIBRARIES_RELEASE) + MARK_AS_ADVANCED(TAGLIB_LIBRARIES_DEBUG) + + ENDIF(NOT WIN32) + + INCLUDE(FindPackageMessage) + INCLUDE(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(Taglib DEFAULT_MSG TAGLIB_INCLUDES TAGLIB_LIBRARIES) + +endif(TAGLIBCONFIG_EXECUTABLE) + + +if(TAGLIB_FOUND) + if(NOT Taglib_FIND_QUIETLY AND TAGLIBCONFIG_EXECUTABLE) + message(STATUS "Taglib found: ${TAGLIB_LIBRARIES}") + endif(NOT Taglib_FIND_QUIETLY AND TAGLIBCONFIG_EXECUTABLE) +else(TAGLIB_FOUND) + if(Taglib_FIND_REQUIRED) + message(FATAL_ERROR "Could not find Taglib") + endif(Taglib_FIND_REQUIRED) +endif(TAGLIB_FOUND) + diff --git a/3rdparty/chromaprint/config.h.in b/3rdparty/chromaprint/config.h.in new file mode 100644 index 000000000..f87db71ad --- /dev/null +++ b/3rdparty/chromaprint/config.h.in @@ -0,0 +1,7 @@ +#cmakedefine HAVE_ROUND 1 +#cmakedefine HAVE_LRINTF 1 +#cmakedefine WITH_AVFFT 1 +#cmakedefine WITH_FFTW3 1 +#cmakedefine WITH_VDSP 1 +#cmakedefine TESTS_DIR "@TESTS_DIR@" + diff --git a/3rdparty/chromaprint/examples/CMakeLists.txt b/3rdparty/chromaprint/examples/CMakeLists.txt new file mode 100644 index 000000000..40bf00395 --- /dev/null +++ b/3rdparty/chromaprint/examples/CMakeLists.txt @@ -0,0 +1,39 @@ +set(EXTRA_LIBS) +if(APPLE) + set(EXTRA_LIBS ${EXTRA_LIBS} -lz) +endif() +if(UNIX) + set(EXTRA_LIBS ${EXTRA_LIBS} -lpthread) +endif() + +set(CMAKE_REQUIRED_LIBRARIES + ${FFMPEG_LIBAVFORMAT_LIBRARIES} + ${FFMPEG_LIBAVCODEC_LIBRARIES} + ${FFMPEG_LIBAVUTIL_LIBRARIES} + ${EXTRA_LIBS}) +check_function_exists(av_audio_convert HAVE_AV_AUDIO_CONVERT) + +if(HAVE_AV_AUDIO_CONVERT) + add_definitions(-DHAVE_AV_AUDIO_CONVERT) +endif() + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/../src + ${FFMPEG_LIBAVCODEC_INCLUDE_DIRS} + ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS} + ${FFMPEG_LIBAVUTIL_INCLUDE_DIRS} +) + +add_executable(fpcalc fpcalc.c) + + +target_link_libraries(fpcalc chromaprint + ${FFMPEG_LIBAVFORMAT_LIBRARIES} + ${FFMPEG_LIBAVCODEC_LIBRARIES} + ${FFMPEG_LIBAVUTIL_LIBRARIES} + ${EXTRA_LIBS}) + +install(TARGETS fpcalc + RUNTIME DESTINATION ${BIN_INSTALL_DIR} +) + diff --git a/3rdparty/chromaprint/examples/ffmpeg/audioconvert.h b/3rdparty/chromaprint/examples/ffmpeg/audioconvert.h new file mode 100644 index 000000000..2b28e2eac --- /dev/null +++ b/3rdparty/chromaprint/examples/ffmpeg/audioconvert.h @@ -0,0 +1,118 @@ +/* + * audio conversion + * Copyright (c) 2006 Michael Niedermayer + * Copyright (c) 2008 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AUDIOCONVERT_H +#define AVCODEC_AUDIOCONVERT_H + +/** + * @file + * Audio format conversion routines + */ + + +#include "libavcodec/avcodec.h" +#include "samplefmt.h" + +#if FF_API_OLD_SAMPLE_FMT +/** + * @deprecated Use av_get_sample_fmt_string() instead. + */ +attribute_deprecated +void avcodec_sample_fmt_string(char *buf, int buf_size, int sample_fmt); + +/** + * @deprecated Use av_get_sample_fmt_name() instead. + */ +attribute_deprecated +const char *avcodec_get_sample_fmt_name(int sample_fmt); + +/** + * @deprecated Use av_get_sample_fmt() instead. + */ +attribute_deprecated +enum AVSampleFormat avcodec_get_sample_fmt(const char* name); +#endif + +#if FF_API_OLD_AUDIOCONVERT +/** + * @deprecated Use av_get_channel_layout() instead. + */ +attribute_deprecated +int64_t avcodec_get_channel_layout(const char *name); + +/** + * @deprecated Use av_get_channel_layout_string() instead. + */ +attribute_deprecated +void avcodec_get_channel_layout_string(char *buf, int buf_size, int nb_channels, int64_t channel_layout); + +/** + * @deprecated Use av_get_channel_layout_nb_channels() instead. + */ +attribute_deprecated +int avcodec_channel_layout_num_channels(int64_t channel_layout); +#endif + +/** + * Guess the channel layout + * @param nb_channels + * @param codec_id Codec identifier, or CODEC_ID_NONE if unknown + * @param fmt_name Format name, or NULL if unknown + * @return Channel layout mask + */ +uint64_t avcodec_guess_channel_layout(int nb_channels, enum CodecID codec_id, const char *fmt_name); + +struct AVAudioConvert; +typedef struct AVAudioConvert AVAudioConvert; + +/** + * Create an audio sample format converter context + * @param out_fmt Output sample format + * @param out_channels Number of output channels + * @param in_fmt Input sample format + * @param in_channels Number of input channels + * @param[in] matrix Channel mixing matrix (of dimension in_channel*out_channels). Set to NULL to ignore. + * @param flags See AV_CPU_FLAG_xx + * @return NULL on error + */ +AVAudioConvert *av_audio_convert_alloc(enum AVSampleFormat out_fmt, int out_channels, + enum AVSampleFormat in_fmt, int in_channels, + const float *matrix, int flags); + +/** + * Free audio sample format converter context + */ +void av_audio_convert_free(AVAudioConvert *ctx); + +/** + * Convert between audio sample formats + * @param[in] out array of output buffers for each channel. set to NULL to ignore processing of the given channel. + * @param[in] out_stride distance between consecutive output samples (measured in bytes) + * @param[in] in array of input buffers for each channel + * @param[in] in_stride distance between consecutive input samples (measured in bytes) + * @param len length of audio frame size (measured in samples) + */ +int av_audio_convert(AVAudioConvert *ctx, + void * const out[6], const int out_stride[6], + const void * const in[6], const int in_stride[6], int len); + +#endif /* AVCODEC_AUDIOCONVERT_H */ diff --git a/3rdparty/chromaprint/examples/ffmpeg/samplefmt.h b/3rdparty/chromaprint/examples/ffmpeg/samplefmt.h new file mode 100644 index 000000000..1d3748130 --- /dev/null +++ b/3rdparty/chromaprint/examples/ffmpeg/samplefmt.h @@ -0,0 +1,156 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SAMPLEFMT_H +#define AVUTIL_SAMPLEFMT_H + +#include "libavutil/avutil.h" + +/** + * all in native-endian format + */ +enum AVSampleFormat { + AV_SAMPLE_FMT_NONE = -1, + AV_SAMPLE_FMT_U8, ///< unsigned 8 bits + AV_SAMPLE_FMT_S16, ///< signed 16 bits + AV_SAMPLE_FMT_S32, ///< signed 32 bits + AV_SAMPLE_FMT_FLT, ///< float + AV_SAMPLE_FMT_DBL, ///< double + + AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar + AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar + AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar + AV_SAMPLE_FMT_FLTP, ///< float, planar + AV_SAMPLE_FMT_DBLP, ///< double, planar + + AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically +}; + +/** + * Return the name of sample_fmt, or NULL if sample_fmt is not + * recognized. + */ +const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt); + +/** + * Return a sample format corresponding to name, or AV_SAMPLE_FMT_NONE + * on error. + */ +enum AVSampleFormat av_get_sample_fmt(const char *name); + +/** + * Return the planar<->packed alternative form of the given sample format, or + * AV_SAMPLE_FMT_NONE on error. If the passed sample_fmt is already in the + * requested planar/packed format, the format returned is the same as the + * input. + */ +enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar); + +/** + * Generate a string corresponding to the sample format with + * sample_fmt, or a header if sample_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param sample_fmt the number of the sample format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + * @return the pointer to the filled buffer or NULL if sample_fmt is + * unknown or in case of other errors + */ +char *av_get_sample_fmt_string(char *buf, int buf_size, enum AVSampleFormat sample_fmt); + +#if FF_API_GET_BITS_PER_SAMPLE_FMT +/** + * @deprecated Use av_get_bytes_per_sample() instead. + */ +attribute_deprecated +int av_get_bits_per_sample_fmt(enum AVSampleFormat sample_fmt); +#endif + +/** + * Return number of bytes per sample. + * + * @param sample_fmt the sample format + * @return number of bytes per sample or zero if unknown for the given + * sample format + */ +int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt); + +/** + * Check if the sample format is planar. + * + * @param sample_fmt the sample format to inspect + * @return 1 if the sample format is planar, 0 if it is interleaved + */ +int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt); + +/** + * Get the required buffer size for the given audio parameters. + * + * @param[out] linesize calculated linesize, may be NULL + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @return required buffer size, or negative error code on failure + */ +int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * Fill channel data pointers and linesize for samples with sample + * format sample_fmt. + * + * The pointers array is filled with the pointers to the samples data: + * for planar, set the start point of each channel's data within the buffer, + * for packed, set the start point of the entire buffer only. + * + * The linesize array is filled with the aligned size of each channel's data + * buffer for planar layout, or the aligned size of the buffer for all channels + * for packed layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize calculated linesize + * @param buf the pointer to a buffer containing the samples + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (1 = no alignment required) + * @return 0 on success or a negative error code on failure + */ +int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, uint8_t *buf, + int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a samples buffer for nb_samples samples, and fill data pointers and + * linesize accordingly. + * The allocated samples buffer can be freed by using av_freep(&audio_data[0]) + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize aligned size for audio buffer(s) + * @param nb_channels number of audio channels + * @param nb_samples number of samples per channel + * @param align buffer size alignment (1 = no alignment required) + * @return 0 on success or a negative error code on failure + * @see av_samples_fill_arrays() + */ +int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +#endif /* AVUTIL_SAMPLEFMT_H */ diff --git a/3rdparty/chromaprint/examples/fpcalc.c b/3rdparty/chromaprint/examples/fpcalc.c new file mode 100644 index 000000000..e8bf7d5f8 --- /dev/null +++ b/3rdparty/chromaprint/examples/fpcalc.c @@ -0,0 +1,303 @@ +#include +#include +#include +#include +#ifdef HAVE_AV_AUDIO_CONVERT +#include "ffmpeg/audioconvert.h" +#include "ffmpeg/samplefmt.h" +#endif +#ifdef _WIN32 +#include +#endif + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define BUFFER_SIZE (AVCODEC_MAX_AUDIO_FRAME_SIZE * 2) + +int decode_audio_file(ChromaprintContext *chromaprint_ctx, int16_t *buffer1, int16_t *buffer2, const char *file_name, int max_length, int *duration) +{ + int i, ok = 0, remaining, length, consumed, buffer_size, codec_ctx_opened = 0; + AVFormatContext *format_ctx = NULL; + AVCodecContext *codec_ctx = NULL; + AVCodec *codec = NULL; + AVStream *stream = NULL; + AVPacket packet, packet_temp; +#ifdef HAVE_AV_AUDIO_CONVERT + AVAudioConvert *convert_ctx = NULL; +#endif + int16_t *buffer; + + if (av_open_input_file(&format_ctx, file_name, NULL, 0, NULL) != 0) { + fprintf(stderr, "ERROR: couldn't open the file\n"); + goto done; + } + + if (av_find_stream_info(format_ctx) < 0) { + fprintf(stderr, "ERROR: couldn't find stream information in the file\n"); + goto done; + } + + for (i = 0; i < format_ctx->nb_streams; i++) { + codec_ctx = format_ctx->streams[i]->codec; +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52, 64, 0) + if (codec_ctx && codec_ctx->codec_type == CODEC_TYPE_AUDIO) { +#else + if (codec_ctx && codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { +#endif + stream = format_ctx->streams[i]; + break; + } + } + if (!stream) { + fprintf(stderr, "ERROR: couldn't find any audio stream in the file\n"); + goto done; + } + + codec = avcodec_find_decoder(codec_ctx->codec_id); + if (!codec) { + fprintf(stderr, "ERROR: unknown codec\n"); + goto done; + } + + if (avcodec_open(codec_ctx, codec) < 0) { + fprintf(stderr, "ERROR: couldn't open the codec\n"); + goto done; + } + codec_ctx_opened = 1; + + if (codec_ctx->channels <= 0) { + fprintf(stderr, "ERROR: no channels found in the audio stream\n"); + goto done; + } + + if (codec_ctx->sample_fmt != SAMPLE_FMT_S16) { +#ifdef HAVE_AV_AUDIO_CONVERT + convert_ctx = av_audio_convert_alloc(SAMPLE_FMT_S16, codec_ctx->channels, + codec_ctx->sample_fmt, codec_ctx->channels, NULL, 0); + if (!convert_ctx) { + fprintf(stderr, "ERROR: couldn't create sample format converter\n"); + goto done; + } +#else + fprintf(stderr, "ERROR: unsupported sample format\n"); + goto done; +#endif + } + + *duration = stream->time_base.num * stream->duration / stream->time_base.den; + + av_init_packet(&packet); + av_init_packet(&packet_temp); + + remaining = max_length * codec_ctx->channels * codec_ctx->sample_rate; + chromaprint_start(chromaprint_ctx, codec_ctx->sample_rate, codec_ctx->channels); + + while (1) { + if (av_read_frame(format_ctx, &packet) < 0) { + break; + } + + packet_temp.data = packet.data; + packet_temp.size = packet.size; + + while (packet_temp.size > 0) { + buffer_size = BUFFER_SIZE; +#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(52, 25, 0) + consumed = avcodec_decode_audio2(codec_ctx, + buffer1, &buffer_size, packet_temp.data, packet_temp.size); +#else + consumed = avcodec_decode_audio3(codec_ctx, + buffer1, &buffer_size, &packet_temp); +#endif + + if (consumed < 0) { + break; + } + + packet_temp.data += consumed; + packet_temp.size -= consumed; + + if (buffer_size <= 0) { + if (buffer_size < 0) { + fprintf(stderr, "WARNING: size returned from avcodec_decode_audioX is too small\n"); + } + continue; + } + if (buffer_size > BUFFER_SIZE) { + fprintf(stderr, "WARNING: size returned from avcodec_decode_audioX is too large\n"); + continue; + } + +#ifdef HAVE_AV_AUDIO_CONVERT + if (convert_ctx) { + const void *ibuf[6] = { buffer1 }; + void *obuf[6] = { buffer2 }; + int istride[6] = { av_get_bits_per_sample_format(codec_ctx->sample_fmt) / 8 }; + int ostride[6] = { 2 }; + int len = buffer_size / istride[0]; + if (av_audio_convert(convert_ctx, obuf, ostride, ibuf, istride, len) < 0) { + break; + } + buffer = buffer2; + buffer_size = len * ostride[0]; + } + else { + buffer = buffer1; + } +#else + buffer = buffer1; +#endif + + length = MIN(remaining, buffer_size / 2); + if (!chromaprint_feed(chromaprint_ctx, buffer, length)) { + fprintf(stderr, "ERROR: fingerprint calculation failed\n"); + goto done; + } + + if (max_length) { + remaining -= length; + if (remaining <= 0) { + goto finish; + } + } + } + + if (packet.data) { + av_free_packet(&packet); + } + } + +finish: + if (!chromaprint_finish(chromaprint_ctx)) { + fprintf(stderr, "ERROR: fingerprint calculation failed\n"); + goto done; + } + + ok = 1; + +done: + if (codec_ctx_opened) { + avcodec_close(codec_ctx); + } + if (format_ctx) { + av_close_input_file(format_ctx); + } +#ifdef HAVE_AV_AUDIO_CONVERT + if (convert_ctx) { + av_audio_convert_free(convert_ctx); + } +#endif + return ok; +} + +int fpcalc_main(int argc, char **argv) +{ + int i, j, max_length = 120, num_file_names = 0, raw = 0, raw_fingerprint_size, duration; + int16_t *buffer1, *buffer2; + int32_t *raw_fingerprint; + char *file_name, *fingerprint, **file_names; + ChromaprintContext *chromaprint_ctx; + + file_names = malloc(argc * sizeof(char *)); + for (i = 1; i < argc; i++) { + char *arg = argv[i]; + if (!strcmp(arg, "-length") && i + 1 < argc) { + max_length = atoi(argv[++i]); + } + else if (!strcmp(arg, "-raw")) { + raw = 1; + } + else { + file_names[num_file_names++] = argv[i]; + } + } + + if (!num_file_names) { + printf("usage: %s [OPTIONS] FILE...\n\n", argv[0]); + printf("Options:\n"); + printf(" -length SECS length of the audio data used for fingerprint calculation (default 120)\n"); + printf(" -raw output the raw uncompressed fingerprint\n"); + return 2; + } + + av_register_all(); + av_log_set_level(AV_LOG_ERROR); + + buffer1 = av_malloc(BUFFER_SIZE + 16); + buffer2 = av_malloc(BUFFER_SIZE + 16); + chromaprint_ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_DEFAULT); + + for (i = 0; i < num_file_names; i++) { + file_name = file_names[i]; + if (!decode_audio_file(chromaprint_ctx, buffer1, buffer2, file_name, max_length, &duration)) { + fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name); + continue; + } + if (i > 0) { + printf("\n"); + } + printf("FILE=%s\n", file_name); + printf("DURATION=%d\n", duration); + if (raw) { + if (!chromaprint_get_raw_fingerprint(chromaprint_ctx, (void **)&raw_fingerprint, &raw_fingerprint_size)) { + fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name); + continue; + } + printf("FINGERPRINT="); + for (j = 0; j < raw_fingerprint_size; j++) { + printf("%d%s", raw_fingerprint[j], j + 1 < raw_fingerprint_size ? "," : "\n"); + } + chromaprint_dealloc(raw_fingerprint); + } + else { + if (!chromaprint_get_fingerprint(chromaprint_ctx, &fingerprint)) { + fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name); + continue; + } + printf("FINGERPRINT=%s\n", fingerprint); + chromaprint_dealloc(fingerprint); + } + } + + chromaprint_free(chromaprint_ctx); + av_free(buffer1); + av_free(buffer2); + free(file_names); + + return 0; +} + +#ifdef _WIN32 +int main(int win32_argc, char **win32_argv) +{ + int i, argc = 0, buffsize = 0, offset = 0; + char **utf8_argv, *utf8_argv_ptr; + wchar_t **argv; + + argv = CommandLineToArgvW(GetCommandLineW(), &argc); + + buffsize = 0; + for (i = 0; i < argc; i++) { + buffsize += WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL); + } + + utf8_argv = av_mallocz(sizeof(char *) * (argc + 1) + buffsize); + utf8_argv_ptr = (char *)utf8_argv + sizeof(char *) * (argc + 1); + + for (i = 0; i < argc; i++) { + utf8_argv[i] = &utf8_argv_ptr[offset]; + offset += WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, &utf8_argv_ptr[offset], buffsize - offset, NULL, NULL); + } + + LocalFree(argv); + + return fpcalc_main(argc, utf8_argv); +} +#else +int main(int argc, char **argv) +{ + return fpcalc_main(argc, argv); +} +#endif + diff --git a/3rdparty/chromaprint/libchromaprint.pc.cmake b/3rdparty/chromaprint/libchromaprint.pc.cmake new file mode 100644 index 000000000..ac94b28da --- /dev/null +++ b/3rdparty/chromaprint/libchromaprint.pc.cmake @@ -0,0 +1,12 @@ +prefix=${CMAKE_INSTALL_PREFIX} +exec_prefix=${EXEC_INSTALL_PREFIX} +libdir=${LIB_INSTALL_DIR} +includedir=${INCLUDE_INSTALL_DIR} + +Name: ${PROJECT_NAME} +Description: Audio fingerprint library +URL: http://wiki.acoustid.org/wiki/Chromaprint +Version: ${PROJECT_VERSION} +Libs: -L${LIB_INSTALL_DIR} -lchromaprint +Cflags: -I${INCLUDE_INSTALL_DIR} + diff --git a/3rdparty/chromaprint/src/CMakeLists.txt b/3rdparty/chromaprint/src/CMakeLists.txt new file mode 100644 index 000000000..cb0afa505 --- /dev/null +++ b/3rdparty/chromaprint/src/CMakeLists.txt @@ -0,0 +1,74 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +set(chromaprint_SRCS + chromaprint.cpp + audio_processor.cpp + chroma.cpp + chroma_resampler.cpp + chroma_filter.cpp + integral_image.cpp + spectrum.cpp + spectral_centroid.cpp + filter.cpp + fft.cpp + fingerprinter.cpp + image_builder.cpp + lloyds.cpp + silence_remover.cpp + fingerprint_calculator.cpp + fingerprint_compressor.cpp + fingerprint_decompressor.cpp + fingerprinter_configuration.cpp + base64.cpp + avresample/resample2.c +) + +if(WITH_AVFFT) + set(chromaprint_SRCS fft_lib_avfft.cpp ${chromaprint_SRCS}) + set(chromaprint_LINK_LIBS + ${FFMPEG_LIBAVCODEC_LIBRARIES} + ${FFMPEG_LIBAVUTIL_LIBRARIES} + ) + include_directories( + ${FFMPEG_LIBAVCODEC_INCLUDE_DIRS} + ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS} + ${FFMPEG_LIBAVUTIL_INCLUDE_DIRS} + ) +endif(WITH_AVFFT) + +if(WITH_FFTW3) + set(chromaprint_SRCS fft_lib_fftw3.cpp ${chromaprint_SRCS}) + set(chromaprint_LINK_LIBS ${FFTW3_LIBRARIES}) + include_directories(${FFTW3_INCLUDE_DIR}) +endif(WITH_FFTW3) + +if(WITH_VDSP) + set(chromaprint_SRCS fft_lib_vdsp.cpp ${chromaprint_SRCS}) + set(chromaprint_LINK_LIBS ${ACCELERATE_LIBRARIES}) +endif() + +add_library(chromaprint_p STATIC ${chromaprint_SRCS}) +target_link_libraries(chromaprint_p ${chromaprint_LINK_LIBS}) + +set(chromaprint_HDRS chromaprint.h) + +add_library(chromaprint ${chromaprint_SRCS} ${chromaprint_SRCS} ${chromaprint_HDRS}) +set_target_properties(chromaprint PROPERTIES + VERSION ${chromaprint_VERSION} + SOVERSION ${chromaprint_SOVERSION} + PUBLIC_HEADER ${chromaprint_HDRS} + DEFINE_SYMBOL CHROMAPRINT_API_EXPORTS +) +if(BUILD_FRAMEWORK) + set_target_properties(chromaprint PROPERTIES FRAMEWORK TRUE) +endif() +target_link_libraries(chromaprint ${chromaprint_LINK_LIBS}) + +install(TARGETS chromaprint + FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR} + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + RUNTIME DESTINATION ${BIN_INSTALL_DIR} + ARCHIVE DESTINATION ${LIB_INSTALL_DIR} + PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR} +) + diff --git a/3rdparty/chromaprint/src/audio_consumer.h b/3rdparty/chromaprint/src/audio_consumer.h new file mode 100644 index 000000000..b5070f640 --- /dev/null +++ b/3rdparty/chromaprint/src/audio_consumer.h @@ -0,0 +1,38 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_AUDIO_CONSUMER_H_ +#define CHROMAPRINT_AUDIO_CONSUMER_H_ + +namespace Chromaprint +{ + + class AudioConsumer + { + public: + virtual ~AudioConsumer() {} + + virtual void Consume(short *input, int length) = 0; + }; + +}; + +#endif + diff --git a/3rdparty/chromaprint/src/audio_processor.cpp b/3rdparty/chromaprint/src/audio_processor.cpp new file mode 100644 index 000000000..5d8a43a97 --- /dev/null +++ b/3rdparty/chromaprint/src/audio_processor.cpp @@ -0,0 +1,191 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include +#include +#include +extern "C" { +#include "avresample/avcodec.h" +} +#include "debug.h" +#include "audio_processor.h" + +using namespace std; +using namespace Chromaprint; + +static const int kMinSampleRate = 1000; +static const int kMaxBufferSize = 1024 * 16; + +// Resampler configuration +static const int kResampleFilterLength = 16; +static const int kResamplePhaseCount = 10; +static const int kResampleLinear = 0; +static const double kResampleCutoff = 0.8; + +AudioProcessor::AudioProcessor(int sample_rate, AudioConsumer *consumer) + : m_buffer_size(kMaxBufferSize), + m_target_sample_rate(sample_rate), + m_consumer(consumer), + m_resample_ctx(0) +{ + m_buffer = new short[kMaxBufferSize]; + m_buffer_offset = 0; + m_resample_buffer = new short[kMaxBufferSize]; +} + +AudioProcessor::~AudioProcessor() +{ + if (m_resample_ctx) { + av_resample_close(m_resample_ctx); + } + delete[] m_resample_buffer; + delete[] m_buffer; +} + +void AudioProcessor::LoadMono(short *input, int length) +{ + short *output = m_buffer + m_buffer_offset; + while (length--) { + *output++ = input[0]; + input++; + } +} + +void AudioProcessor::LoadStereo(short *input, int length) +{ + short *output = m_buffer + m_buffer_offset; + while (length--) { + *output++ = (input[0] + input[1]) / 2; + input += 2; + } +} + +void AudioProcessor::LoadMultiChannel(short *input, int length) +{ + short *output = m_buffer + m_buffer_offset; + while (length--) { + long sum = 0; + for (int i = 0; i < m_num_channels; i++) { + sum += *input++; + } + *output++ = (short)(sum / m_num_channels); + } +} + +int AudioProcessor::Load(short *input, int length) +{ + assert(length >= 0); + assert(m_buffer_offset <= m_buffer_size); + length = min(length, m_buffer_size - m_buffer_offset); + switch (m_num_channels) { + case 1: + LoadMono(input, length); + break; + case 2: + LoadStereo(input, length); + break; + default: + LoadMultiChannel(input, length); + break; + } + m_buffer_offset += length; + return length; +} + +void AudioProcessor::Resample() +{ + if (!m_resample_ctx) { + m_consumer->Consume(m_buffer, m_buffer_offset); + m_buffer_offset = 0; + return; + } + int consumed = 0; + int length = av_resample(m_resample_ctx, m_resample_buffer, m_buffer, &consumed, m_buffer_offset, kMaxBufferSize, 1); + if (length > kMaxBufferSize) { + DEBUG() << "Chromaprint::AudioProcessor::Resample() -- Resampling overwrote output buffer.\n"; + length = kMaxBufferSize; + } + m_consumer->Consume(m_resample_buffer, length); + int remaining = m_buffer_offset - consumed; + if (remaining > 0) { + copy(m_buffer + consumed, m_buffer + m_buffer_offset, m_buffer); + } + else if (remaining < 0) { + DEBUG() << "Chromaprint::AudioProcessor::Resample() -- Resampling overread input buffer.\n"; + remaining = 0; + } + m_buffer_offset = remaining; +} + + +bool AudioProcessor::Reset(int sample_rate, int num_channels) +{ + if (num_channels <= 0) { + DEBUG() << "Chromaprint::AudioProcessor::Reset() -- No audio channels.\n"; + return false; + } + if (sample_rate <= kMinSampleRate) { + DEBUG() << "Chromaprint::AudioProcessor::Reset() -- Sample rate less " + << "than " << kMinSampleRate << " (" << sample_rate << ").\n"; + return false; + } + m_buffer_offset = 0; + if (m_resample_ctx) { + av_resample_close(m_resample_ctx); + m_resample_ctx = 0; + } + if (sample_rate != m_target_sample_rate) { + m_resample_ctx = av_resample_init( + m_target_sample_rate, sample_rate, + kResampleFilterLength, + kResamplePhaseCount, + kResampleLinear, + kResampleCutoff); + } + m_num_channels = num_channels; + return true; +} + +void AudioProcessor::Consume(short *input, int length) +{ + assert(length >= 0); + assert(length % m_num_channels == 0); + length /= m_num_channels; + while (length > 0) { + int consumed = Load(input, length); + input += consumed * m_num_channels; + length -= consumed; + if (m_buffer_size == m_buffer_offset) { + Resample(); + if (m_buffer_size == m_buffer_offset) { + DEBUG() << "Chromaprint::AudioProcessor::Consume() -- Resampling failed?\n"; + return; + } + } + } +} + +void AudioProcessor::Flush() +{ + if (m_buffer_offset) { + Resample(); + } +} + diff --git a/3rdparty/chromaprint/src/audio_processor.h b/3rdparty/chromaprint/src/audio_processor.h new file mode 100644 index 000000000..917805427 --- /dev/null +++ b/3rdparty/chromaprint/src/audio_processor.h @@ -0,0 +1,87 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_AUDIO_PROCESSOR_H_ +#define CHROMAPRINT_AUDIO_PROCESSOR_H_ + +#include "utils.h" +#include "audio_consumer.h" + +struct AVResampleContext; + +namespace Chromaprint +{ + + class AudioProcessor : public AudioConsumer + { + public: + AudioProcessor(int sample_rate, AudioConsumer *consumer); + virtual ~AudioProcessor(); + + int target_sample_rate() const + { + return m_target_sample_rate; + } + + void set_target_sample_rate(int sample_rate) + { + m_target_sample_rate = sample_rate; + } + + AudioConsumer *consumer() const + { + return m_consumer; + } + + void set_consumer(AudioConsumer *consumer) + { + m_consumer = consumer; + } + + //! Prepare for a new audio stream + bool Reset(int sample_rate, int num_channels); + //! Process a chunk of data from the audio stream + void Consume(short *input, int length); + //! Process any buffered input that was not processed before and clear buffers + void Flush(); + + private: + CHROMAPRINT_DISABLE_COPY(AudioProcessor); + + int Load(short *input, int length); + void LoadMono(short *input, int length); + void LoadStereo(short *input, int length); + void LoadMultiChannel(short *input, int length); + void Resample(); + + short *m_buffer; + short *m_resample_buffer; + int m_buffer_offset; + int m_buffer_size; + int m_target_sample_rate; + int m_num_channels; + AudioConsumer *m_consumer; + struct AVResampleContext *m_resample_ctx; + }; + +}; + +#endif + diff --git a/3rdparty/chromaprint/src/avresample/avcodec.h b/3rdparty/chromaprint/src/avresample/avcodec.h new file mode 100644 index 000000000..9df0b22dd --- /dev/null +++ b/3rdparty/chromaprint/src/avresample/avcodec.h @@ -0,0 +1,101 @@ +/* + * copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_H +#define AVCODEC_H + +/* Just a heavily bastardized version of the original file from + * ffmpeg, just enough to get resample2.c to compile without + * modification -- Lennart */ + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +typedef void *AVClass; + +#define av_mallocz(l) calloc(1, (l)) +#define av_malloc(l) malloc(l) +#define av_realloc(p,l) realloc((p),(l)) +#define av_free(p) free(p) + +#ifdef _MSC_VER +#define CHROMAPRINT_C_INLINE __inline +#else +#define CHROMAPRINT_C_INLINE inline +#endif + +static CHROMAPRINT_C_INLINE void av_freep(void *k) { + void **p = (void **)k; + + if (p) { + free(*p); + *p = NULL; + } +} + +static CHROMAPRINT_C_INLINE int av_clip(int a, int amin, int amax) +{ + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +#define av_log(a,b,c) + +#define FFABS(a) ((a) >= 0 ? (a) : (-(a))) +#define FFSIGN(a) ((a) > 0 ? 1 : -1) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) + +struct AVResampleContext; +struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff); +int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx); +void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance); +void av_resample_close(struct AVResampleContext *c); +void av_build_filter(int16_t *filter, double factor, int tap_count, int phase_count, int scale, int type); + +/* error handling */ +#if EDOM > 0 +#define AVERROR(e) (-(e)) ///< Returns a negative error code from a POSIX error code, to return from library functions. +#define AVUNERROR(e) (-(e)) ///< Returns a POSIX error code from a library function error return value. +#else +/* Some platforms have E* and errno already negated. */ +#define AVERROR(e) (e) +#define AVUNERROR(e) (e) +#endif + +/* + * crude lrintf for non-C99 systems. + */ +#ifndef HAVE_LRINTF +#define lrintf(x) ((long int)floor(x + 0.5)) +#endif + +#endif /* AVCODEC_H */ diff --git a/3rdparty/chromaprint/src/avresample/dsputil.h b/3rdparty/chromaprint/src/avresample/dsputil.h new file mode 100644 index 000000000..8da742d0f --- /dev/null +++ b/3rdparty/chromaprint/src/avresample/dsputil.h @@ -0,0 +1 @@ +/* empty file, just here to allow us to compile an unmodified resampler2.c */ diff --git a/3rdparty/chromaprint/src/avresample/resample2.c b/3rdparty/chromaprint/src/avresample/resample2.c new file mode 100644 index 000000000..b940059d8 --- /dev/null +++ b/3rdparty/chromaprint/src/avresample/resample2.c @@ -0,0 +1,320 @@ +/* + * audio resampling + * Copyright (c) 2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * audio resampling + * @author Michael Niedermayer + */ + +#include "avcodec.h" +#include "dsputil.h" + +#ifndef CONFIG_RESAMPLE_HP +#define FILTER_SHIFT 15 + +#define FELEM int16_t +#define FELEM2 int32_t +#define FELEML int64_t +#define FELEM_MAX INT16_MAX +#define FELEM_MIN INT16_MIN +#define WINDOW_TYPE 9 +#elif !defined(CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE) +#define FILTER_SHIFT 30 + +#define FELEM int32_t +#define FELEM2 int64_t +#define FELEML int64_t +#define FELEM_MAX INT32_MAX +#define FELEM_MIN INT32_MIN +#define WINDOW_TYPE 12 +#else +#define FILTER_SHIFT 0 + +#define FELEM double +#define FELEM2 double +#define FELEML double +#define WINDOW_TYPE 24 +#endif + + +typedef struct AVResampleContext{ + const AVClass *av_class; + FELEM *filter_bank; + int filter_length; + int ideal_dst_incr; + int dst_incr; + int index; + int frac; + int src_incr; + int compensation_distance; + int phase_shift; + int phase_mask; + int linear; +}AVResampleContext; + +/** + * 0th order modified bessel function of the first kind. + */ +static double bessel(double x){ + double v=1; + double lastv=0; + double t=1; + int i; + + x= x*x/4; + for(i=1; v != lastv; i++){ + lastv=v; + t *= x/(i*i); + v += t; + } + return v; +} + +/** + * builds a polyphase filterbank. + * @param factor resampling factor + * @param scale wanted sum of coefficients for each filter + * @param type 0->cubic, 1->blackman nuttall windowed sinc, 2..16->kaiser windowed sinc beta=2..16 + * @return 0 on success, negative on error + */ +static int build_filter(FELEM *filter, double factor, int tap_count, int phase_count, int scale, int type){ + int ph, i; + double x, y, w; + double *tab = av_malloc(tap_count * sizeof(*tab)); + const int center= (tap_count-1)/2; + + if (!tab) + return AVERROR(ENOMEM); + + /* if upsampling, only need to interpolate, no filter */ + if (factor > 1.0) + factor = 1.0; + + for(ph=0;phphase_shift= phase_shift; + c->phase_mask= phase_count-1; + c->linear= linear; + + c->filter_length= FFMAX((int)ceil(filter_size/factor), 1); + c->filter_bank= av_mallocz(c->filter_length*(phase_count+1)*sizeof(FELEM)); + if (!c->filter_bank) + goto error; + if (build_filter(c->filter_bank, factor, c->filter_length, phase_count, 1<filter_bank[c->filter_length*phase_count+1], c->filter_bank, (c->filter_length-1)*sizeof(FELEM)); + c->filter_bank[c->filter_length*phase_count]= c->filter_bank[c->filter_length - 1]; + + c->src_incr= out_rate; + c->ideal_dst_incr= c->dst_incr= in_rate * phase_count; + c->index= -phase_count*((c->filter_length-1)/2); + + return c; +error: + av_free(c->filter_bank); + av_free(c); + return NULL; +} + +void av_resample_close(AVResampleContext *c){ + av_freep(&c->filter_bank); + av_freep(&c); +} + +void av_resample_compensate(AVResampleContext *c, int sample_delta, int compensation_distance){ +// sample_delta += (c->ideal_dst_incr - c->dst_incr)*(int64_t)c->compensation_distance / c->ideal_dst_incr; + c->compensation_distance= compensation_distance; + c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * (int64_t)sample_delta / compensation_distance; +} + +int av_resample(AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx){ + int dst_index, i; + int index= c->index; + int frac= c->frac; + int dst_incr_frac= c->dst_incr % c->src_incr; + int dst_incr= c->dst_incr / c->src_incr; + int compensation_distance= c->compensation_distance; + + if(compensation_distance == 0 && c->filter_length == 1 && c->phase_shift==0){ + int64_t index2= ((int64_t)index)<<32; + int64_t incr= (1LL<<32) * c->dst_incr / c->src_incr; + dst_size= FFMIN(dst_size, (src_size-1-index) * (int64_t)c->src_incr / c->dst_incr); + + for(dst_index=0; dst_index < dst_size; dst_index++){ + dst[dst_index] = src[index2>>32]; + index2 += incr; + } + frac += dst_index * dst_incr_frac; + index += dst_index * dst_incr; + index += frac / c->src_incr; + frac %= c->src_incr; + }else{ + for(dst_index=0; dst_index < dst_size; dst_index++){ + FELEM *filter= c->filter_bank + c->filter_length*(index & c->phase_mask); + int sample_index= index >> c->phase_shift; + FELEM2 val=0; + + if(sample_index < 0){ + for(i=0; ifilter_length; i++) + val += src[FFABS(sample_index + i) % src_size] * filter[i]; + }else if(sample_index + c->filter_length > src_size){ + break; + }else if(c->linear){ + FELEM2 v2=0; + for(i=0; ifilter_length; i++){ + val += src[sample_index + i] * (FELEM2)filter[i]; + v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_length]; + } + val+=(v2-val)*(FELEML)frac / c->src_incr; + }else{ + for(i=0; ifilter_length; i++){ + val += src[sample_index + i] * (FELEM2)filter[i]; + } + } + +#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE + dst[dst_index] = av_clip_int16(lrintf(val)); +#else + val = (val + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT; + dst[dst_index] = (unsigned)(val + 32768) > 65535 ? (val>>31) ^ 32767 : val; +#endif + + frac += dst_incr_frac; + index += dst_incr; + if(frac >= c->src_incr){ + frac -= c->src_incr; + index++; + } + + if(dst_index + 1 == compensation_distance){ + compensation_distance= 0; + dst_incr_frac= c->ideal_dst_incr % c->src_incr; + dst_incr= c->ideal_dst_incr / c->src_incr; + } + } + } + *consumed= FFMAX(index, 0) >> c->phase_shift; + if(index>=0) index &= c->phase_mask; + + if(compensation_distance){ + compensation_distance -= dst_index; + assert(compensation_distance > 0); + } + if(update_ctx){ + c->frac= frac; + c->index= index; + c->dst_incr= dst_incr_frac + c->src_incr*dst_incr; + c->compensation_distance= compensation_distance; + } +#if 0 + if(update_ctx && !c->compensation_distance){ +#undef rand + av_resample_compensate(c, rand() % (8000*2) - 8000, 8000*2); +av_log(NULL, AV_LOG_DEBUG, "%d %d %d\n", c->dst_incr, c->ideal_dst_incr, c->compensation_distance); + } +#endif + + return dst_index; +} diff --git a/3rdparty/chromaprint/src/base64.cpp b/3rdparty/chromaprint/src/base64.cpp new file mode 100644 index 000000000..0eb37c79a --- /dev/null +++ b/3rdparty/chromaprint/src/base64.cpp @@ -0,0 +1,92 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include +#include +#include "base64.h" +#include "bit_string_writer.h" +#include "debug.h" + +using namespace std; +using namespace Chromaprint; + +static const char kBase64Chars[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; +static const char kBase64CharsReversed[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0 +}; + +string Chromaprint::Base64Encode(const string &orig) +{ + int size = orig.size(); + int encoded_size = (size * 4 + 2) / 3; + string encoded(encoded_size, '\x00'); + const unsigned char *src = (unsigned char *)orig.data(); + string::iterator dest = encoded.begin(); + while (size > 0) { + *dest++ = kBase64Chars[(src[0] >> 2)]; + *dest++ = kBase64Chars[((src[0] << 4) | (--size ? (src[1] >> 4) : 0)) & 63]; + if (size) { + *dest++ = kBase64Chars[((src[1] << 2) | (--size ? (src[2] >> 6) : 0)) & 63]; + if (size) { + *dest++ = kBase64Chars[src[2] & 63]; + --size; + } + } + src += 3; + } + return encoded; +} + +string Chromaprint::Base64Decode(const string &encoded) +{ + string str((3 * encoded.size()) / 4, '\x00'); + const unsigned char *src = (const unsigned char *)encoded.data(); + int size = encoded.size(); + string::iterator dest = str.begin(); + while (size > 0) { + int b0 = kBase64CharsReversed[*src++]; + if (--size) { + int b1 = kBase64CharsReversed[*src++]; + int r = (b0 << 2) | (b1 >> 4); + assert(dest != str.end()); + *dest++ = r; + if (--size) { + int b2 = kBase64CharsReversed[*src++]; + r = ((b1 << 4) & 255) | (b2 >> 2); + assert(dest != str.end()); + *dest++ = r; + if (--size) { + int b3 = kBase64CharsReversed[*src++]; + r = ((b2 << 6) & 255) | b3; + assert(dest != str.end()); + *dest++ = r; + --size; + } + } + } + } + return str; +} + diff --git a/3rdparty/chromaprint/src/base64.h b/3rdparty/chromaprint/src/base64.h new file mode 100644 index 000000000..bcae7ac09 --- /dev/null +++ b/3rdparty/chromaprint/src/base64.h @@ -0,0 +1,35 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_BASE64_H_ +#define CHROMAPRINT_BASE64_H_ + +#include + +namespace Chromaprint +{ + + std::string Base64Encode(const std::string &str); + std::string Base64Decode(const std::string &encoded); + +}; + +#endif + diff --git a/3rdparty/chromaprint/src/bit_string_reader.h b/3rdparty/chromaprint/src/bit_string_reader.h new file mode 100644 index 000000000..ecf78e0fa --- /dev/null +++ b/3rdparty/chromaprint/src/bit_string_reader.h @@ -0,0 +1,69 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_BIT_STRING_READER_H_ +#define CHROMAPRINT_BIT_STRING_READER_H_ + +#include +#include +#include "debug.h" + +namespace Chromaprint +{ + class BitStringReader + { + public: + BitStringReader(const std::string &input) : m_value(input), m_buffer(0), m_buffer_size(0) + { + m_value_iter = m_value.begin(); + } + + uint32_t Read(int bits) + { + if (m_buffer_size < bits) { + if (m_value_iter != m_value.end()) { + m_buffer |= (unsigned char)(*m_value_iter++) << m_buffer_size; + m_buffer_size += 8; + } + } + uint32_t result = m_buffer & ((1 << bits) - 1); + m_buffer >>= bits; + m_buffer_size -= bits; + return result; + } + + void Reset() + { + m_buffer = 0; + m_buffer_size = 0; + } + + private: + + std::string m_value; + std::string::iterator m_value_iter; + uint32_t m_buffer; + int m_buffer_size; + }; + +}; + +#endif + diff --git a/3rdparty/chromaprint/src/bit_string_writer.h b/3rdparty/chromaprint/src/bit_string_writer.h new file mode 100644 index 000000000..c28ca273a --- /dev/null +++ b/3rdparty/chromaprint/src/bit_string_writer.h @@ -0,0 +1,77 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_BIT_STRING_WRITER_H_ +#define CHROMAPRINT_BIT_STRING_WRITER_H_ + +#include +#include +#include + +namespace Chromaprint +{ + class Classifier; + class Image; + class IntegralImage; + + class BitStringWriter + { + public: + BitStringWriter() : m_buffer(0), m_buffer_size(0) + { + } + + void Write(uint32_t x, int bits) + { + m_buffer |= (x << m_buffer_size); + m_buffer_size += bits; + while (m_buffer_size >= 8) { + m_value.push_back(m_buffer & 255); + m_buffer >>= 8; + m_buffer_size -= 8; + } + } + + void Flush() + { + while (m_buffer_size > 0) { + m_value.push_back(m_buffer & 255); + m_buffer >>= 8; + m_buffer_size -= 8; + } + m_buffer_size = 0; + } + + std::string value() const + { + return m_value; + } + + private: + + std::string m_value; + uint32_t m_buffer; + int m_buffer_size; + }; + +}; + +#endif + diff --git a/3rdparty/chromaprint/src/chroma.cpp b/3rdparty/chromaprint/src/chroma.cpp new file mode 100644 index 000000000..b19d0a58e --- /dev/null +++ b/3rdparty/chromaprint/src/chroma.cpp @@ -0,0 +1,95 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include +#include +#include "fft_frame.h" +#include "utils.h" +#include "chroma.h" +#include "debug.h" + +using namespace std; +using namespace Chromaprint; + +static const int NUM_BANDS = 12; + +inline double FreqToOctave(double freq, double base = 440.0 / 16.0) +{ + return log(freq / base) / log(2.0); +} + +Chroma::Chroma(int min_freq, int max_freq, int frame_size, int sample_rate, FeatureVectorConsumer *consumer) + : m_interpolate(false), + m_notes(frame_size), + m_notes_frac(frame_size), + m_features(NUM_BANDS), + m_consumer(consumer) +{ + PrepareNotes(min_freq, max_freq, frame_size, sample_rate); +} + +Chroma::~Chroma() +{ +} + +void Chroma::PrepareNotes(int min_freq, int max_freq, int frame_size, int sample_rate) +{ + m_min_index = max(1, FreqToIndex(min_freq, frame_size, sample_rate)); + m_max_index = min(frame_size / 2, FreqToIndex(max_freq, frame_size, sample_rate)); + for (int i = m_min_index; i < m_max_index; i++) { + double freq = IndexToFreq(i, frame_size, sample_rate); + double octave = FreqToOctave(freq); + double note = NUM_BANDS * (octave - floor(octave)); + m_notes[i] = (char)note; + m_notes_frac[i] = note - m_notes[i]; + } +} + +void Chroma::Reset() +{ +} + +void Chroma::Consume(const FFTFrame &frame) +{ + fill(m_features.begin(), m_features.end(), 0.0); + for (int i = m_min_index; i < m_max_index; i++) { + int note = m_notes[i]; + double energy = frame.Energy(i); + if (m_interpolate) { + int note2 = note; + double a = 1.0; + if (m_notes_frac[i] < 0.5) { + note2 = (note + NUM_BANDS - 1) % NUM_BANDS; + a = 0.5 + m_notes_frac[i]; + } + if (m_notes_frac[i] > 0.5) { + note2 = (note + 1) % NUM_BANDS; + a = 1.5 - m_notes_frac[i]; + } + m_features[note] += energy * a; + m_features[note2] += energy * (1.0 - a); + } + else { + m_features[note] += energy; + } + } + m_consumer->Consume(m_features); +} + diff --git a/3rdparty/chromaprint/src/chroma.h b/3rdparty/chromaprint/src/chroma.h new file mode 100644 index 000000000..0183ac1b4 --- /dev/null +++ b/3rdparty/chromaprint/src/chroma.h @@ -0,0 +1,68 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_CHROMA_H_ +#define CHROMAPRINT_CHROMA_H_ + +#include +#include +#include "utils.h" +#include "fft_frame_consumer.h" +#include "feature_vector_consumer.h" + +namespace Chromaprint +{ + + class Chroma : public FFTFrameConsumer + { + public: + Chroma(int min_freq, int max_freq, int frame_size, int sample_rate, FeatureVectorConsumer *consumer); + ~Chroma(); + + bool interpolate() const + { + return m_interpolate; + } + + void set_interpolate(bool interpolate) + { + m_interpolate = interpolate; + } + + void Reset(); + void Consume(const FFTFrame &frame); + + private: + CHROMAPRINT_DISABLE_COPY(Chroma); + + void PrepareNotes(int min_freq, int max_freq, int frame_size, int sample_rate); + + bool m_interpolate; + std::vector m_notes; + std::vector m_notes_frac; + int m_min_index; + int m_max_index; + std::vector m_features; + FeatureVectorConsumer *m_consumer; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/chroma_filter.cpp b/3rdparty/chromaprint/src/chroma_filter.cpp new file mode 100644 index 000000000..202c3aa34 --- /dev/null +++ b/3rdparty/chromaprint/src/chroma_filter.cpp @@ -0,0 +1,69 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include +#include +#include +#include "chroma_filter.h" +#include "utils.h" + +using namespace std; +using namespace Chromaprint; + +ChromaFilter::ChromaFilter(const double *coefficients, int length, FeatureVectorConsumer *consumer) + : m_coefficients(coefficients), + m_length(length), + m_buffer(8), + m_result(12), + m_buffer_offset(0), + m_buffer_size(1), + m_consumer(consumer) +{ +} + +ChromaFilter::~ChromaFilter() +{ +} + +void ChromaFilter::Reset() +{ + m_buffer_size = 1; + m_buffer_offset = 0; +} + +void ChromaFilter::Consume(std::vector &features) +{ + m_buffer[m_buffer_offset] = features; + m_buffer_offset = (m_buffer_offset + 1) % 8; + if (m_buffer_size >= m_length) { + int offset = (m_buffer_offset + 8 - m_length) % 8; + fill(m_result.begin(), m_result.end(), 0.0); + for (int i = 0; i < 12; i++) { + for (int j = 0; j < m_length; j++) { + m_result[i] += m_buffer[(offset + j) % 8][i] * m_coefficients[j]; + } + } + m_consumer->Consume(m_result); + } + else { + m_buffer_size++; + } +} + diff --git a/3rdparty/chromaprint/src/chroma_filter.h b/3rdparty/chromaprint/src/chroma_filter.h new file mode 100644 index 000000000..69f6febdc --- /dev/null +++ b/3rdparty/chromaprint/src/chroma_filter.h @@ -0,0 +1,54 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_CHROMA_FILTER_H_ +#define CHROMAPRINT_CHROMA_FILTER_H_ + +#include +#include "feature_vector_consumer.h" + +namespace Chromaprint +{ + + class ChromaFilter : public FeatureVectorConsumer + { + public: + ChromaFilter(const double *coefficients, int length, FeatureVectorConsumer *consumer); + ~ChromaFilter(); + + void Reset(); + void Consume(std::vector &features); + + FeatureVectorConsumer *consumer() { return m_consumer; } + void set_consumer(FeatureVectorConsumer *consumer) { m_consumer = consumer; } + + private: + const double *m_coefficients; + int m_length; + std::vector< std::vector > m_buffer; + std::vector m_result; + int m_buffer_offset; + int m_buffer_size; + FeatureVectorConsumer *m_consumer; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/chroma_normalizer.h b/3rdparty/chromaprint/src/chroma_normalizer.h new file mode 100644 index 000000000..33f1ffd6e --- /dev/null +++ b/3rdparty/chromaprint/src/chroma_normalizer.h @@ -0,0 +1,55 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_CHROMA_NORMALIZER_H_ +#define CHROMAPRINT_CHROMA_NORMALIZER_H_ + +#include +#include +#include "feature_vector_consumer.h" +#include "utils.h" + +namespace Chromaprint +{ + + class ChromaNormalizer : public FeatureVectorConsumer + { + public: + ChromaNormalizer(FeatureVectorConsumer *consumer) : m_consumer(consumer) {} + ~ChromaNormalizer() {} + void Reset() {} + + void Consume(std::vector &features) + { + NormalizeVector(features.begin(), features.end(), + Chromaprint::EuclideanNorm::iterator>, + 0.01); + m_consumer->Consume(features); + } + + private: + CHROMAPRINT_DISABLE_COPY(ChromaNormalizer); + + FeatureVectorConsumer *m_consumer; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/chroma_resampler.cpp b/3rdparty/chromaprint/src/chroma_resampler.cpp new file mode 100644 index 000000000..6be6c1324 --- /dev/null +++ b/3rdparty/chromaprint/src/chroma_resampler.cpp @@ -0,0 +1,62 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include +#include +#include +#include "chroma_resampler.h" +#include "utils.h" + +using namespace std; +using namespace Chromaprint; + +ChromaResampler::ChromaResampler(int factor, FeatureVectorConsumer *consumer) + : m_result(12, 0.0), + m_iteration(0), + m_factor(factor), + m_consumer(consumer) +{ +} + +ChromaResampler::~ChromaResampler() +{ +} + +void ChromaResampler::Reset() +{ + m_iteration = 0; + fill(m_result.begin(), m_result.end(), 0.0); +} + +void ChromaResampler::Consume(std::vector &features) +{ + for (int i = 0; i < 12; i++) { + m_result[i] += features[i]; + } + m_iteration += 1; + if (m_iteration == m_factor) { + for (int i = 0; i < 12; i++) { + m_result[i] /= m_factor; + } + m_consumer->Consume(m_result); + Reset(); + } +} + diff --git a/3rdparty/chromaprint/src/chroma_resampler.h b/3rdparty/chromaprint/src/chroma_resampler.h new file mode 100644 index 000000000..36eff29e8 --- /dev/null +++ b/3rdparty/chromaprint/src/chroma_resampler.h @@ -0,0 +1,52 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_CHROMA_RESAMPLER_H_ +#define CHROMAPRINT_CHROMA_RESAMPLER_H_ + +#include +#include "image.h" +#include "feature_vector_consumer.h" + +namespace Chromaprint +{ + + class ChromaResampler : public FeatureVectorConsumer + { + public: + ChromaResampler(int factor, FeatureVectorConsumer *consumer); + ~ChromaResampler(); + + void Reset(); + void Consume(std::vector &features); + + FeatureVectorConsumer *consumer() { return m_consumer; } + void set_consumer(FeatureVectorConsumer *consumer) { m_consumer = consumer; } + + private: + std::vector m_result; + int m_iteration; + int m_factor; + FeatureVectorConsumer *m_consumer; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/chromaprint.cpp b/3rdparty/chromaprint/src/chromaprint.cpp new file mode 100644 index 000000000..0b9792b19 --- /dev/null +++ b/3rdparty/chromaprint/src/chromaprint.cpp @@ -0,0 +1,150 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include +#include +#include +#include +#include "fingerprinter.h" +#include "fingerprint_compressor.h" +#include "fingerprint_decompressor.h" +#include "fingerprinter_configuration.h" +#include "base64.h" + +using namespace std; +using namespace Chromaprint; + +extern "C" { + +struct ChromaprintContextPrivate { + int algorithm; + Fingerprinter *fingerprinter; + vector fingerprint; +}; + +#define STR(x) #x +#define VERSION_STR(minor, major, patch) \ + STR(major) "." STR(minor) "." STR(patch) + +static const char *version_str = VERSION_STR( + CHROMAPRINT_VERSION_MAJOR, + CHROMAPRINT_VERSION_MINOR, + CHROMAPRINT_VERSION_PATCH); + +const char *chromaprint_get_version(void) +{ + return version_str; +} + +ChromaprintContext *chromaprint_new(int algorithm) +{ + ChromaprintContextPrivate *ctx = new ChromaprintContextPrivate(); + ctx->algorithm = algorithm; + ctx->fingerprinter = new Fingerprinter(CreateFingerprinterConfiguration(algorithm)); + return (ChromaprintContext *)ctx; +} + +void chromaprint_free(ChromaprintContext *c) +{ + ChromaprintContextPrivate *ctx = (ChromaprintContextPrivate *)c; + delete ctx->fingerprinter; + delete ctx; +} + +int chromaprint_start(ChromaprintContext *c, int sample_rate, int num_channels) +{ + ChromaprintContextPrivate *ctx = (ChromaprintContextPrivate *)c; + return ctx->fingerprinter->Start(sample_rate, num_channels) ? 1 : 0; +} + +int chromaprint_feed(ChromaprintContext *c, void *data, int length) +{ + ChromaprintContextPrivate *ctx = (ChromaprintContextPrivate *)c; + ctx->fingerprinter->Consume((short *)data, length); + return 1; +} + +int chromaprint_finish(ChromaprintContext *c) +{ + ChromaprintContextPrivate *ctx = (ChromaprintContextPrivate *)c; + ctx->fingerprint = ctx->fingerprinter->Finish(); + return 1; +} + +int chromaprint_get_fingerprint(ChromaprintContext *c, char **data) +{ + ChromaprintContextPrivate *ctx = (ChromaprintContextPrivate *)c; + string fp = Chromaprint::Base64Encode(Chromaprint::CompressFingerprint(ctx->fingerprint, ctx->algorithm)); + *data = (char *)malloc(fp.size() + 1); + if (!*data) { + return 0; + } + copy(fp.begin(), fp.end(), *data); + (*data)[fp.size()] = 0; + return 1; +} + +int chromaprint_get_raw_fingerprint(ChromaprintContext *c, void **data, int *size) +{ + ChromaprintContextPrivate *ctx = (ChromaprintContextPrivate *)c; + *data = malloc(sizeof(int32_t) * ctx->fingerprint.size()); + if (!*data) { + return 0; + } + *size = ctx->fingerprint.size(); + copy(ctx->fingerprint.begin(), ctx->fingerprint.end(), *((int32_t **)data)); + return 1; +} + +int chromaprint_encode_fingerprint(void *fp, int size, int algorithm, void **encoded_fp, int *encoded_size, int base64) +{ + vector uncompressed = vector((int32_t *)fp, (int32_t *)fp + size); + string compressed = Chromaprint::CompressFingerprint(uncompressed, algorithm); + if (!base64) { + *encoded_fp = malloc(compressed.size()); + *encoded_size = compressed.size(); + copy(compressed.begin(), compressed.end(), (char *)*encoded_fp); + return 1; + } + string encoded = Chromaprint::Base64Encode(compressed); + *encoded_fp = malloc(encoded.size() + 1); + *encoded_size = encoded.size(); + copy(encoded.begin(), encoded.end(), (char *)*encoded_fp); + ((char *)*encoded_fp)[encoded.size()] = 0; + return 1; +} + +int chromaprint_decode_fingerprint(void *encoded_fp, int encoded_size, void **fp, int *size, int *algorithm, int base64) +{ + string encoded = string((char *)encoded_fp, encoded_size); + string compressed = base64 ? Chromaprint::Base64Decode(encoded) : encoded; + vector uncompressed = Chromaprint::DecompressFingerprint(compressed, algorithm); + *fp = malloc(sizeof(int32_t) * uncompressed.size()); + *size = uncompressed.size(); + copy(uncompressed.begin(), uncompressed.end(), (int32_t *)*fp); + return 0; +} + +void chromaprint_dealloc(void *ptr) +{ + free(ptr); +} + +} diff --git a/3rdparty/chromaprint/src/chromaprint.h b/3rdparty/chromaprint/src/chromaprint.h new file mode 100644 index 000000000..e7cbe89d0 --- /dev/null +++ b/3rdparty/chromaprint/src/chromaprint.h @@ -0,0 +1,222 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_CHROMAPRINT_H_ +#define CHROMAPRINT_CHROMAPRINT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if (defined(_WIN32) || defined(_WIN64)) +# ifdef CHROMAPRINT_NODLL +# define CHROMAPRINT_API +# else +# ifdef CHROMAPRINT_API_EXPORTS +# define CHROMAPRINT_API __declspec(dllexport) +# else +# define CHROMAPRINT_API __declspec(dllimport) +# endif +# endif +#else +# if __GNUC__ >= 4 +# define CHROMAPRINT_API __attribute__ ((visibility("default"))) +# else +# define CHROMAPRINT_API +# endif +#endif + +typedef void *ChromaprintContext; + +#define CHROMAPRINT_VERSION_MAJOR 0 +#define CHROMAPRINT_VERSION_MINOR 6 +#define CHROMAPRINT_VERSION_PATCH 0 + +enum ChromaprintAlgorithm { + CHROMAPRINT_ALGORITHM_TEST1 = 0, + CHROMAPRINT_ALGORITHM_TEST2, + CHROMAPRINT_ALGORITHM_TEST3 +}; + +#define CHROMAPRINT_ALGORITHM_DEFAULT CHROMAPRINT_ALGORITHM_TEST2 + +/** + * Return the version number of Chromaprint. + */ +CHROMAPRINT_API const char *chromaprint_get_version(void); + +/** + * Allocate and initialize the Chromaprint context. + * + * Parameters: + * - version: Version of the fingerprint algorithm, use + * CHROMAPRINT_ALGORITHM_DEFAULT for the default + * algorithm + * + * Returns: + * - Chromaprint context pointer + */ +CHROMAPRINT_API ChromaprintContext *chromaprint_new(int algorithm); + +/** + * Deallocate the Chromaprint context. + * + * Parameters: + * - ctx: Chromaprint context pointer + */ +CHROMAPRINT_API void chromaprint_free(ChromaprintContext *ctx); + +/** + * Return the fingerprint algorithm this context is configured to use. + */ +CHROMAPRINT_API int chromaprint_get_algorithm(ChromaprintContext *ctx); + +/** + * Restart the computation of a fingerprint with a new audio stream. + * + * Parameters: + * - ctx: Chromaprint context pointer + * - sample_rate: sample rate of the audio stream (in Hz) + * - num_channels: numbers of channels in the audio stream (1 or 2) + * + * Returns: + * - 0 on error, 1 on success + */ +CHROMAPRINT_API int chromaprint_start(ChromaprintContext *ctx, int sample_rate, int num_channels); + +/** + * Send audio data to the fingerprint calculator. + * + * Parameters: + * - ctx: Chromaprint context pointer + * - data: raw audio data, should point to an array of 16-bit signed + * integers in native byte-order + * - size: size of the data buffer (in samples) + * + * Returns: + * - 0 on error, 1 on success + */ +CHROMAPRINT_API int chromaprint_feed(ChromaprintContext *ctx, void *data, int size); + +/** + * Process any remaining buffered audio data and calculate the fingerprint. + * + * Parameters: + * - ctx: Chromaprint context pointer + * + * Returns: + * - 0 on error, 1 on success + */ +CHROMAPRINT_API int chromaprint_finish(ChromaprintContext *ctx); + +/** + * Return the calculated fingerprint as a compressed string. + * + * The caller is responsible for freeing the returned pointer using + * chromaprint_dealloc(). + * + * Parameters: + * - ctx: Chromaprint context pointer + * - fingerprint: pointer to a pointer, where a pointer to the allocated array + * will be stored + * + * Returns: + * - 0 on error, 1 on success + */ +CHROMAPRINT_API int chromaprint_get_fingerprint(ChromaprintContext *ctx, char **fingerprint); + +/** + * Return the calculated fingerprint as an array of 32-bit integers. + * + * The caller is responsible for freeing the returned pointer using + * chromaprint_dealloc(). + * + * Parameters: + * - ctx: Chromaprint context pointer + * - fingerprint: pointer to a pointer, where a pointer to the allocated array + * will be stored + * - size: number of items in the returned raw fingerprint + * + * Returns: + * - 0 on error, 1 on success + */ +CHROMAPRINT_API int chromaprint_get_raw_fingerprint(ChromaprintContext *ctx, void **fingerprint, int *size); + +/** + * Compress and optionally base64-encode a raw fingerprint + * + * The caller is responsible for freeing the returned pointer using + * chromaprint_dealloc(). + * + * Parameters: + * - fp: pointer to an array of 32-bit integers representing the raw + * fingerprint to be encoded + * - size: number of items in the raw fingerprint + * - algorithm: Chromaprint algorithm version which was used to generate the + * raw fingerprint + * - encoded_fp: pointer to a pointer, where the encoded fingerprint will be + * stored + * - encoded_size: size of the encoded fingerprint in bytes + * - base64: Whether to return binary data or base64-encoded ASCII data. The + * compressed fingerprint will be encoded using base64 with the + * URL-safe scheme if you set this parameter to 1. It will return + * binary data if it's 0. + * + * Returns: + * - 0 on error, 1 on success + */ +CHROMAPRINT_API int chromaprint_encode_fingerprint(void *fp, int size, int algorithm, void **encoded_fp, int *encoded_size, int base64); + +/** + * Uncompress and optionally base64-decode an encoded fingerprint + * + * The caller is responsible for freeing the returned pointer using + * chromaprint_dealloc(). + * + * Parameters: + * - encoded_fp: Pointer to an encoded fingerprint + * - encoded_size: Size of the encoded fingerprint in bytes + * - fp: Pointer to a pointer, where the decoded raw fingerprint (array + * of 32-bit integers) will be stored + * - size: Number of items in the returned raw fingerprint + * - algorithm: Chromaprint algorithm version which was used to generate the + * raw fingerprint + * - base64: Whether the encoded_fp parameter contains binary data or + * base64-encoded ASCII data. If 1, it will base64-decode the data + * before uncompressing the fingerprint. + * + * Returns: + * - 0 on error, 1 on success + */ +CHROMAPRINT_API int chromaprint_decode_fingerprint(void *encoded_fp, int encoded_size, void **fp, int *size, int *algorithm, int base64); + +/** + * Free memory allocated by any function from the Chromaprint API. + * + * Parameters: + * - ptr: Pointer to be deallocated + */ +CHROMAPRINT_API void chromaprint_dealloc(void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/3rdparty/chromaprint/src/classifier.h b/3rdparty/chromaprint/src/classifier.h new file mode 100644 index 000000000..919e64273 --- /dev/null +++ b/3rdparty/chromaprint/src/classifier.h @@ -0,0 +1,61 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_CLASSIFIER_H_ +#define CHROMAPRINT_CLASSIFIER_H_ + +#include +#include "quantizer.h" +#include "filter.h" +#include "integral_image.h" + +namespace Chromaprint +{ + + class Classifier + { + public: + Classifier(const Filter &filter = Filter(), const Quantizer &quantizer = Quantizer()) + : m_filter(filter), m_quantizer(quantizer) + { + } + + int Classify(IntegralImage *image, int offset) const + { + double value = m_filter.Apply(image, offset); + return m_quantizer.Quantize(value); + } + + const Filter &filter() const { return m_filter; } + const Quantizer &quantizer() const { return m_quantizer; } + + private: + Filter m_filter; + Quantizer m_quantizer; + }; + + inline std::ostream &operator<<(std::ostream &stream, const Classifier &q) + { + stream << "Classifier(" << q.filter() << ", " << q.quantizer() << ")"; + return stream; + } +}; + +#endif diff --git a/3rdparty/chromaprint/src/combined_buffer.h b/3rdparty/chromaprint/src/combined_buffer.h new file mode 100644 index 000000000..68eb3fbbc --- /dev/null +++ b/3rdparty/chromaprint/src/combined_buffer.h @@ -0,0 +1,176 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_COMBINED_BUFFER_H_ +#define CHROMAPRINT_COMBINED_BUFFER_H_ + +#include +#include +#include + +namespace Chromaprint +{ + + template + class CombinedBuffer; + + template + class _CombinedBufferIterator + { + public: + typedef std::input_iterator_tag iterator_category; + typedef T value_type; + typedef int difference_type; + typedef T* pointer; + typedef T& reference; + + _CombinedBufferIterator(CombinedBuffer *buffer = 0, int pos = 0) + : m_buffer(buffer) + { + pos += buffer->Offset(); + if (pos < buffer->BufferSize(0)) { + m_ptr = buffer->Buffer(0) + pos; + m_ptr_end = buffer->Buffer(0) + buffer->BufferSize(0); + } + else { + pos -= buffer->BufferSize(0); + m_ptr = buffer->Buffer(1) + pos; + m_ptr_end = buffer->Buffer(1) + buffer->BufferSize(1); + } + } + + _CombinedBufferIterator &operator=(const _CombinedBufferIterator &rhs) + { + m_buffer = rhs.m_buffer; + m_ptr = rhs.m_ptr; + m_ptr_end = rhs.m_pre_end; + return *this; + } + + bool operator==(const _CombinedBufferIterator &rhs) const + { + return (m_ptr == rhs.m_ptr) && (m_buffer == rhs.m_buffer); + } + + bool operator!=(const _CombinedBufferIterator &rhs) const + { + return !(operator==(rhs)); + } + + void operator++() + { + ++m_ptr; + if (m_ptr >= m_ptr_end) { + if (m_ptr_end == m_buffer->Buffer(0) + m_buffer->BufferSize(0)) { + m_ptr = m_buffer->Buffer(1); + m_ptr_end = m_buffer->Buffer(1) + m_buffer->BufferSize(1); + } + } + } + + void operator++(int) + { + ++(*this); + } + + short &operator*() + { + assert(m_ptr); + return *m_ptr; + } + + private: + CombinedBuffer *m_buffer; + T *m_ptr_end; + T *m_ptr; + }; + + template + class CombinedBuffer + { + public: + typedef _CombinedBufferIterator Iterator; + + CombinedBuffer(T *buffer1, int size1, T *buffer2, int size2) + : m_offset(0) + { + m_buffer[0] = buffer1; + m_buffer[1] = buffer2; + m_buffer[2] = 0; + m_size[0] = size1; + m_size[1] = size2; + m_size[2] = -1; + } + + int Size() + { + return m_size[0] + m_size[1] - m_offset; + } + + int Shift(int shift) + { + m_offset += shift; + return m_offset; + } + + int Offset() const + { + return m_offset; + } + + Iterator Begin() + { + return Iterator(this, 0); + } + + Iterator End() + { + return Iterator(this, Size()); + } + + T &operator[](int i) + { + i += m_offset; + if (i < m_size[0]) { + return m_buffer[0][i]; + } + i -= m_size[0]; + return m_buffer[1][i]; + } + + T *Buffer(int i) + { + return m_buffer[i]; + } + + int BufferSize(int i) + { + return m_size[i]; + } + + private: + T *m_buffer[3]; + int m_size[3]; + int m_offset; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/debug.h b/3rdparty/chromaprint/src/debug.h new file mode 100644 index 000000000..075cdf8cf --- /dev/null +++ b/3rdparty/chromaprint/src/debug.h @@ -0,0 +1,42 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_DEBUG_H_ +#define CHROMAPRINT_DEBUG_H_ + +#ifdef NDEBUG +#include +#else +#include +#endif + +namespace Chromaprint +{ + +#ifdef NDEBUG +extern std::ostream noop_ostream; +#define DEBUG() if (true) {} else noop_ostream +#else +#define DEBUG() std::cerr +#endif + +}; + +#endif diff --git a/3rdparty/chromaprint/src/decoder.h b/3rdparty/chromaprint/src/decoder.h new file mode 100644 index 000000000..77e24fbfb --- /dev/null +++ b/3rdparty/chromaprint/src/decoder.h @@ -0,0 +1,15 @@ +#ifndef CHROMAPRINT_DECODER_H_ +#define CHROMAPRINT_DECODER_H_ + +namespace Chromaprint +{ + + class Decoder + { + public: + + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/ext/audio_dumper.h b/3rdparty/chromaprint/src/ext/audio_dumper.h new file mode 100644 index 000000000..b7795b6e6 --- /dev/null +++ b/3rdparty/chromaprint/src/ext/audio_dumper.h @@ -0,0 +1,30 @@ +#ifndef CHROMAPRINT_EXT_AUDIO_DUMPER_H_ +#define CHROMAPRINT_EXT_AUDIO_DUMPER_H_ + +#include +#include +#include "audio_consumer.h" + +class AudioDumper : public Chromaprint::AudioConsumer +{ +public: + AudioDumper(const std::string &file_name) + { + m_file = fopen(file_name.c_str(), "wb"); + } + + ~AudioDumper() + { + fclose(m_file); + } + + void Consume(short *input, int length) + { + fwrite(input, sizeof(short), length, m_file); + } + +private: + FILE *m_file; +}; + +#endif diff --git a/3rdparty/chromaprint/src/ext/ffmpeg_decoder.h b/3rdparty/chromaprint/src/ext/ffmpeg_decoder.h new file mode 100644 index 000000000..f8d34c714 --- /dev/null +++ b/3rdparty/chromaprint/src/ext/ffmpeg_decoder.h @@ -0,0 +1,230 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef FFMPEG_DECODER_H_ +#define FFMPEG_DECODER_H_ + +#include +extern "C" { +#include +#include +} +#include "audio_consumer.h" + +class Decoder +{ +public: + Decoder(const std::string &file_name); + ~Decoder(); + + bool Open(); + void Decode(Chromaprint::AudioConsumer *consumer, int max_length = 0); + + int Channels() + { + return m_codec_ctx->channels; + } + + int SampleRate() + { + return m_codec_ctx->sample_rate; + } + + std::string LastError() + { + return m_error; + } + +private: + static const int BUFFER_SIZE = AVCODEC_MAX_AUDIO_FRAME_SIZE * 2; + uint8_t *m_buffer1; + uint8_t *m_buffer2; + std::string m_file_name; + std::string m_error; + AVFormatContext *m_format_ctx; + AVCodecContext *m_codec_ctx; + AVStream *m_stream; + //AVAudioConvert *m_convert_ctx; +}; + +inline Decoder::Decoder(const std::string &file_name) + : m_file_name(file_name), m_format_ctx(0), m_codec_ctx(0), m_stream(0) + /*, m_convert_ctx(0)*/ +{ + av_register_all(); + av_log_set_level(AV_LOG_ERROR); + m_buffer1 = (uint8_t *)av_malloc(BUFFER_SIZE); + m_buffer2 = (uint8_t *)av_malloc(BUFFER_SIZE); +} + +inline Decoder::~Decoder() +{ + if (m_codec_ctx) { + avcodec_close(m_codec_ctx); + } + if (m_format_ctx) { + av_close_input_file(m_format_ctx); + } + //av_audio_convert_free(m_convert_ctx); + av_free(m_buffer2); + av_free(m_buffer1); +} + +inline bool Decoder::Open() +{ + if (av_open_input_file(&m_format_ctx, m_file_name.c_str(), NULL, 0, NULL) != 0) { + m_error = "Couldn't open the file." + m_file_name; + return false; + } + + if (av_find_stream_info(m_format_ctx) < 0) { + m_error = "Couldn't find stream information in the file."; + return false; + } + + //dump_format(m_format_ctx, 0, m_file_name.c_str(), 0); + + for (size_t i = 0; i < m_format_ctx->nb_streams; i++) { + AVCodecContext *avctx = m_format_ctx->streams[i]->codec; +#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(52, 20, 0) + if (avctx && avctx->codec_type == CODEC_TYPE_AUDIO) { +#else + if (avctx && avctx->codec_type == AVMEDIA_TYPE_AUDIO) { +#endif + m_stream = m_format_ctx->streams[i]; + m_codec_ctx = avctx; + break; + } + } + if (!m_codec_ctx) { + m_error = "Couldn't find any audio stream in the file."; + return false; + } + + AVCodec *codec = avcodec_find_decoder(m_codec_ctx->codec_id); + if (!codec) { + m_error = "Unknown codec."; + return false; + } + + if (avcodec_open(m_codec_ctx, codec) < 0) { + m_error = "Couldn't open the codec."; + return false; + } + + if (m_codec_ctx->sample_fmt != SAMPLE_FMT_S16) { + m_error = "Unsupported sample format.\n"; + return false; + } + /*m_convert_ctx = av_audio_convert_alloc(SAMPLE_FMT_S16, 1, + m_codec_ctx->sample_fmt, 1, + NULL, 0); + if (!m_convert_ctx) { + m_error = "Cannot create sample format converter."; + return false; + }*/ + + if (Channels() <= 0) { + m_error = "Invalid audio stream (no channels).\n"; + return false; + } + + return true; +} + +#include + +inline void Decoder::Decode(Chromaprint::AudioConsumer *consumer, int max_length) +{ + AVPacket packet, packet_temp; + + int remaining = max_length * SampleRate() * Channels(); + int stop = 0; + + av_init_packet(&packet); + av_init_packet(&packet_temp); + while (!stop) { + if (av_read_frame(m_format_ctx, &packet) < 0) { + // consumer->Flush(); + break; + } + + packet_temp.data = packet.data; + packet_temp.size = packet.size; + while (packet_temp.size > 0) { + int buffer_size = BUFFER_SIZE; +#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(52, 20, 0) + int consumed = avcodec_decode_audio2( + m_codec_ctx, (int16_t *)m_buffer1, &buffer_size, + packet_temp.data, packet_temp.size); +#else + int consumed = avcodec_decode_audio3( + m_codec_ctx, (int16_t *)m_buffer1, &buffer_size, + &packet_temp); +#endif + + if (consumed < 0) { + break; + } + + packet_temp.data += consumed; + packet_temp.size -= consumed; + + if (buffer_size <= 0) { + continue; + } + + int length = buffer_size / 2; + int16_t *audio_buffer = (int16_t *)m_buffer1; + + /*if (m_convert_ctx) { + const void *ibuf[6] = { m_buffer1 }; + void *obuf[6] = { m_buffer2 }; + int istride[6] = { av_get_bits_per_sample_format(m_codec_ctx->sample_fmt) / 8 }; + int ostride[6] = { 2 }; + if (av_audio_convert(m_convert_ctx, obuf, ostride, ibuf, istride, len) < 0) { + break; + } + length = buffer_size / istride[0]; + audio_buffer = (int16_t *)m_buffer2; + }*/ + + if (max_length) { + length = std::min(remaining, length); + } + + consumer->Consume(audio_buffer, length); + + if (max_length) { + remaining -= length; + if (remaining <= 0) { + stop = 1; + break; + } + } + } + + if (packet.data) { + av_free_packet(&packet); + } + } +} + +#endif diff --git a/3rdparty/chromaprint/src/ext/image_utils.cpp b/3rdparty/chromaprint/src/ext/image_utils.cpp new file mode 100644 index 000000000..3bcdd7a41 --- /dev/null +++ b/3rdparty/chromaprint/src/ext/image_utils.cpp @@ -0,0 +1,27 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include +#include "image_utils.h" + +using namespace std; +using namespace Chromaprint; + + diff --git a/3rdparty/chromaprint/src/ext/image_utils.h b/3rdparty/chromaprint/src/ext/image_utils.h new file mode 100644 index 000000000..a0e702788 --- /dev/null +++ b/3rdparty/chromaprint/src/ext/image_utils.h @@ -0,0 +1,108 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_EXT_IMAGE_UTILS_H_ +#define CHROMAPRINT_EXT_IMAGE_UTILS_H_ + +#include +#include +#include +#include +#include +#include "image.h" + +namespace Chromaprint +{ + + //! Export image to a PNG file + inline void ExportImage(Image *data, const std::string &file_name, double power = 1.0) + { + static const int kNumColors = 6; + static int colors[][3] = { + { 0, 0, 0 }, + { 218, 38, 0 }, + { 221, 99, 0 }, + { 255, 253, 0 }, + { 255, 254, 83 }, + { 255, 255, 200 }, + { 255, 255, 255 }, + }; + + png::image image(data->NumRows(), data->NumColumns()); + double min_value = (*data)[0][0], max_value = (*data)[0][0]; + for (size_t y = 0; y < data->NumRows(); y++) { + for (size_t x = 0; x < data->NumColumns(); x++) { + double value = (*data)[y][x]; + min_value = std::min(min_value, value); + max_value = std::max(max_value, value); + } + } + //std::cout << "min_value=" << min_value << "\n"; + //std::cout << "max_value=" << max_value << "\n"; + for (size_t y = 0; y < data->NumRows(); y++) { + for (size_t x = 0; x < data->NumColumns(); x++) { + double value = ((*data)[y][x] - min_value) / (max_value - min_value); + value = pow(value, power); + double color_value = kNumColors * value; + int color_index = int(color_value); + double color_alpha = color_value - color_index; + if (color_index < 0) { + color_index = 0; + color_alpha = 0; + } + else if (color_index > kNumColors) { + color_index = kNumColors; + color_alpha = 0; + } + //std::cout << "value=" << color_value << "\n"; + //std::cout << "alpha=" << color_alpha << "\n"; + int r = colors[color_index][0] + (colors[color_index+1][0] - colors[color_index][0]) * color_alpha; + int g = colors[color_index][1] + (colors[color_index+1][1] - colors[color_index][1]) * color_alpha; + int b = colors[color_index][2] + (colors[color_index+1][2] - colors[color_index][2]) * color_alpha; + //int color = 255 * vlue + 0.5; + image[data->NumColumns()-x-1][y] = png::rgb_pixel(r, g, b); + } + } + image.write(file_name); + } + + //! Export image in a text format (floating point numbers) to any stream + template + void ExportTextImage(ImageType *image, std::ostream &stream) + { + for (int i = 0; i < image->NumRows(); i++) { + for (int j = 0; j < image->NumColumns(); j++) { + stream << image->Row(i)[j] << " "; + } + stream << "\n"; + } + } + + //! Export image in a text format (floating point numbers) to a file + template + void ExportTextImage(ImageType *image, const std::string &file_name) + { + std::fstream out(file_name.c_str(), std::ios::out); + ExportTextImage(image, out); + } + +}; + +#endif diff --git a/3rdparty/chromaprint/src/ext/sox_decoder.h b/3rdparty/chromaprint/src/ext/sox_decoder.h new file mode 100644 index 000000000..8cf0cfe82 --- /dev/null +++ b/3rdparty/chromaprint/src/ext/sox_decoder.h @@ -0,0 +1,101 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef FFMPEG_DECODER_H_ +#define FFMPEG_DECODER_H_ + +#include +extern "C" { +#include +#include +} +#include "sox_audio_source.h" +#include "audio_consumer.h" + +class Decoder +{ +public: + Decoder(const std::string &file_name); + ~Decoder(); + + bool Open(); + void Decode(Chromaprint::AudioConsumer *consumer, int max_length = 0); + + int Channels() + { + return m_source->Channels(); + } + + int SampleRate() + { + return m_source->SampleRate(); + } + + std::string LastError() + { + return ""; + // return m_error; + } + +private: + SoxAudioSource *m_source; + short m_buffer[1024]; +}; + +inline Decoder::Decoder(const std::string &file_name) +{ + m_source = new SoxAudioSource(file_name); + m_source->Open(); +} + +inline Decoder::~Decoder() +{ + delete m_source; +} + +inline bool Decoder::Open() +{ + return true; +} + +#include + +inline void Decoder::Decode(Chromaprint::AudioConsumer *consumer, int max_length) +{ + int remaining = SampleRate() * Channels() * max_length; + while (true) { + int res = m_source->Read(m_buffer, size_t(1024)); + if (res <= 0) { + break; + } + if (max_length) { + res = std::min(res, remaining); + } + consumer->Consume(m_buffer, res); + if (max_length) { + remaining -= res; + if (res <= 0) { + break; + } + } + } +} + +#endif diff --git a/3rdparty/chromaprint/src/feature_vector_consumer.h b/3rdparty/chromaprint/src/feature_vector_consumer.h new file mode 100644 index 000000000..305aed970 --- /dev/null +++ b/3rdparty/chromaprint/src/feature_vector_consumer.h @@ -0,0 +1,39 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FEATURE_VECTOR_CONSUMER_H_ +#define CHROMAPRINT_FEATURE_VECTOR_CONSUMER_H_ + +#include + +namespace Chromaprint +{ + + class FeatureVectorConsumer + { + public: + virtual ~FeatureVectorConsumer() {} + virtual void Consume(std::vector &features) = 0; + }; + +}; + +#endif + diff --git a/3rdparty/chromaprint/src/fft.cpp b/3rdparty/chromaprint/src/fft.cpp new file mode 100644 index 000000000..406f8a969 --- /dev/null +++ b/3rdparty/chromaprint/src/fft.cpp @@ -0,0 +1,77 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include +#include "utils.h" +#include "fft_lib.h" +#include "fft.h" +#include "debug.h" + +using namespace std; +using namespace Chromaprint; + +FFT::FFT(int frame_size, int overlap, FFTFrameConsumer *consumer) + : m_window(new double[frame_size]), + m_buffer_offset(0), + m_buffer(new short[frame_size]), + m_frame(frame_size), + m_frame_size(frame_size), + m_increment(frame_size - overlap), + m_consumer(consumer) +{ + PrepareHammingWindow(m_window, m_window + frame_size); + for (int i = 0; i < frame_size; i++) { + m_window[i] /= numeric_limits::max(); + } + m_lib = new FFTLib(frame_size, m_window); +} + +FFT::~FFT() +{ + delete m_lib; + delete[] m_buffer; + delete[] m_window; +} + +void FFT::Reset() +{ + m_buffer_offset = 0; +} + +void FFT::Consume(short *input, int length) +{ + // Special case, just pre-filling the buffer + if (m_buffer_offset + length < m_frame_size) { + copy(input, input + length, m_buffer + m_buffer_offset); + m_buffer_offset += length; + return; + } + // Apply FFT on the available data + CombinedBuffer combined_buffer(m_buffer, m_buffer_offset, input, length); + while (combined_buffer.Size() >= m_frame_size) { + m_lib->ComputeFrame(combined_buffer.Begin(), m_frame.data()); + m_consumer->Consume(m_frame); + combined_buffer.Shift(m_increment); + } + // Copy the remaining input data to the internal buffer + copy(combined_buffer.Begin(), combined_buffer.End(), m_buffer); + m_buffer_offset = combined_buffer.Size(); +} + diff --git a/3rdparty/chromaprint/src/fft.h b/3rdparty/chromaprint/src/fft.h new file mode 100644 index 000000000..4657e9195 --- /dev/null +++ b/3rdparty/chromaprint/src/fft.h @@ -0,0 +1,62 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FFT_H_ +#define CHROMAPRINT_FFT_H_ + +#include +#include "utils.h" +#include "fft_frame.h" +#include "fft_frame_consumer.h" +#include "audio_consumer.h" +#include "combined_buffer.h" + +namespace Chromaprint +{ + class FFTLib; + + class FFT : public AudioConsumer + { + public: + FFT(int frame_size, int overlap, FFTFrameConsumer *consumer); + ~FFT(); + + int FrameSize() const { return m_frame_size; } + int Overlap() const { return m_frame_size - m_increment; } + + void Reset(); + void Consume(short *input, int length); + + private: + CHROMAPRINT_DISABLE_COPY(FFT); + + double *m_window; + int m_buffer_offset; + short *m_buffer; + FFTFrame m_frame; + int m_frame_size; + int m_increment; + FFTLib *m_lib; + FFTFrameConsumer *m_consumer; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/fft_frame.h b/3rdparty/chromaprint/src/fft_frame.h new file mode 100644 index 000000000..d39dddcf9 --- /dev/null +++ b/3rdparty/chromaprint/src/fft_frame.h @@ -0,0 +1,69 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FFT_FRAME_H_ +#define CHROMAPRINT_FFT_FRAME_H_ + +#include + +namespace Chromaprint +{ + + class FFTFrame + { + public: + FFTFrame(int size) : m_size(size) + { + m_data = new double[size]; + } + + ~FFTFrame() + { + delete[] m_data; + } + + double Magnitude(int i) const + { + return sqrt(Energy(i)); + } + + double Energy(int i) const + { + return m_data[i]; + } + + int size() const + { + return m_size; + } + + double *data() + { + return m_data; + } + + private: + double *m_data; + int m_size; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/fft_frame_consumer.h b/3rdparty/chromaprint/src/fft_frame_consumer.h new file mode 100644 index 000000000..9952232ea --- /dev/null +++ b/3rdparty/chromaprint/src/fft_frame_consumer.h @@ -0,0 +1,38 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FFT_FRAME_CONSUMER_H_ +#define CHROMAPRINT_FFT_FRAME_CONSUMER_H_ + +namespace Chromaprint +{ + + class FFTFrame; + + class FFTFrameConsumer + { + public: + virtual ~FFTFrameConsumer() {} + virtual void Consume(const FFTFrame &frame) = 0; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/fft_lib.h b/3rdparty/chromaprint/src/fft_lib.h new file mode 100644 index 000000000..dc621a3aa --- /dev/null +++ b/3rdparty/chromaprint/src/fft_lib.h @@ -0,0 +1,40 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FFT_LIB_H_ +#define CHROMAPRINT_FFT_LIB_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef WITH_AVFFT +#include "fft_lib_avfft.h" +#endif + +#ifdef WITH_FFTW3 +#include "fft_lib_fftw3.h" +#endif + +#ifdef WITH_VDSP +#include "fft_lib_vdsp.h" +#endif + +#endif diff --git a/3rdparty/chromaprint/src/fft_lib_avfft.cpp b/3rdparty/chromaprint/src/fft_lib_avfft.cpp new file mode 100644 index 000000000..768440084 --- /dev/null +++ b/3rdparty/chromaprint/src/fft_lib_avfft.cpp @@ -0,0 +1,60 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include "utils.h" +#include "fft_lib_avfft.h" + +using namespace std; +using namespace Chromaprint; + +FFTLib::FFTLib(int frame_size, double *window) + : m_window(window), + m_frame_size(frame_size) +{ + m_input = (float *)av_mallocz(sizeof(float) * frame_size); + int bits = -1; + while (frame_size) { + bits++; + frame_size >>= 1; + } + m_rdft_ctx = av_rdft_init(bits, DFT_R2C); +} + +FFTLib::~FFTLib() +{ + av_rdft_end(m_rdft_ctx); + av_free(m_input); +} + +void FFTLib::ComputeFrame(CombinedBuffer::Iterator input, double *output) +{ + ApplyWindow(input, m_window, m_input, m_frame_size, 1.0); + av_rdft_calc(m_rdft_ctx, m_input); + float *in_ptr = m_input; + output[0] = in_ptr[0] * in_ptr[0]; + output[m_frame_size / 2] = in_ptr[1] * in_ptr[1]; + output += 1; + in_ptr += 2; + for (int i = 1; i < m_frame_size / 2; i++) { + *output++ = in_ptr[0] * in_ptr[0] + in_ptr[1] * in_ptr[1]; + in_ptr += 2; + } +} + diff --git a/3rdparty/chromaprint/src/fft_lib_avfft.h b/3rdparty/chromaprint/src/fft_lib_avfft.h new file mode 100644 index 000000000..87c8034d4 --- /dev/null +++ b/3rdparty/chromaprint/src/fft_lib_avfft.h @@ -0,0 +1,53 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FFT_LIB_AVFFT_H_ +#define CHROMAPRINT_FFT_LIB_AVFFT_H_ + +#include +extern "C" { +#include +#include +} +#include "combined_buffer.h" + +namespace Chromaprint +{ + + class FFTLib + { + public: + FFTLib(int frame_size, double *window); + ~FFTLib(); + + void ComputeFrame(CombinedBuffer::Iterator input, double *output); + + private: + CHROMAPRINT_DISABLE_COPY(FFTLib); + + double *m_window; + int m_frame_size; + float *m_input; + RDFTContext *m_rdft_ctx; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/fft_lib_fftw3.cpp b/3rdparty/chromaprint/src/fft_lib_fftw3.cpp new file mode 100644 index 000000000..f8beb21c0 --- /dev/null +++ b/3rdparty/chromaprint/src/fft_lib_fftw3.cpp @@ -0,0 +1,58 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include "utils.h" +#include "fft_lib_fftw3.h" + +using namespace std; +using namespace Chromaprint; + +FFTLib::FFTLib(int frame_size, double *window) + : m_frame_size(frame_size), + m_window(window) +{ + m_input = (double *)fftw_malloc(sizeof(double) * frame_size); + m_output = (double *)fftw_malloc(sizeof(double) * frame_size); + m_plan = fftw_plan_r2r_1d(frame_size, m_input, m_output, FFTW_R2HC, FFTW_ESTIMATE); +} + +FFTLib::~FFTLib() +{ + fftw_destroy_plan(m_plan); + fftw_free(m_input); + fftw_free(m_output); +} + +void FFTLib::ComputeFrame(CombinedBuffer::Iterator input, double *output) +{ + ApplyWindow(input, m_window, m_input, m_frame_size, 1.0); + fftw_execute(m_plan); + double *in_ptr = m_output; + double *rev_in_ptr = m_output + m_frame_size - 1; + output[0] = in_ptr[0] * in_ptr[0]; + output[m_frame_size / 2] = in_ptr[m_frame_size / 2] * in_ptr[m_frame_size / 2]; + in_ptr += 1; + output += 1; + for (int i = 1; i < m_frame_size / 2; i++) { + *output++ = in_ptr[0] * in_ptr[0] + rev_in_ptr[0] * rev_in_ptr[0]; + in_ptr++; + rev_in_ptr--; + } +} diff --git a/3rdparty/chromaprint/src/fft_lib_fftw3.h b/3rdparty/chromaprint/src/fft_lib_fftw3.h new file mode 100644 index 000000000..a21a564d3 --- /dev/null +++ b/3rdparty/chromaprint/src/fft_lib_fftw3.h @@ -0,0 +1,51 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FFT_LIB_FFTW3_H_ +#define CHROMAPRINT_FFT_LIB_FFTW3_H_ + +#include +#include +#include "combined_buffer.h" + +namespace Chromaprint +{ + + class FFTLib + { + public: + FFTLib(int frame_size, double *window); + ~FFTLib(); + + void ComputeFrame(CombinedBuffer::Iterator input, double *output); + + private: + CHROMAPRINT_DISABLE_COPY(FFTLib); + + double *m_window; + int m_frame_size; + double *m_input; + double *m_output; + fftw_plan m_plan; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/fft_lib_vdsp.cpp b/3rdparty/chromaprint/src/fft_lib_vdsp.cpp new file mode 100644 index 000000000..a15e6199a --- /dev/null +++ b/3rdparty/chromaprint/src/fft_lib_vdsp.cpp @@ -0,0 +1,61 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2011 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include "utils.h" +#include "fft_lib_vdsp.h" + +using namespace std; +using namespace Chromaprint; + +FFTLib::FFTLib(int frame_size, double *window) + : m_window(window), + m_frame_size(frame_size) +{ + double log2n = log2(frame_size); + assert(log2n == int(log2n)); + m_log2n = int(log2n); + m_input = new float[frame_size]; + m_a.realp = new float[frame_size / 2]; + m_a.imagp = new float[frame_size / 2]; + m_setup = vDSP_create_fftsetup(m_log2n, 0); +} + +FFTLib::~FFTLib() +{ + vDSP_destroy_fftsetup(m_setup); + delete[] m_a.realp; + delete[] m_a.imagp; + delete[] m_input; +} + +void FFTLib::ComputeFrame(CombinedBuffer::Iterator input, double *output) +{ + ApplyWindow(input, m_window, m_input, m_frame_size, 1.0); + // XXX we can avoid this ctoz call by changing ApplyWindow, is it worth it? + vDSP_ctoz((DSPComplex *)m_input, 2, &m_a, 1, m_frame_size / 2); + vDSP_fft_zrip(m_setup, &m_a, 1, m_log2n, FFT_FORWARD); + output[0] = m_a.realp[0] * m_a.realp[0]; + output[m_frame_size / 2] = m_a.imagp[0] * m_a.imagp[0]; + output += 1; + for (int i = 1; i < m_frame_size / 2; i++) { + *output++ = m_a.realp[i] * m_a.realp[i] + m_a.imagp[i] * m_a.imagp[i]; + } +} + diff --git a/3rdparty/chromaprint/src/fft_lib_vdsp.h b/3rdparty/chromaprint/src/fft_lib_vdsp.h new file mode 100644 index 000000000..dd7fcc335 --- /dev/null +++ b/3rdparty/chromaprint/src/fft_lib_vdsp.h @@ -0,0 +1,52 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2011 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FFT_LIB_VDSP_H_ +#define CHROMAPRINT_FFT_LIB_VDSP_H_ + +#include +#include +#include "combined_buffer.h" + +namespace Chromaprint +{ + + class FFTLib + { + public: + FFTLib(int frame_size, double *window); + ~FFTLib(); + + void ComputeFrame(CombinedBuffer::Iterator input, double *output); + + private: + CHROMAPRINT_DISABLE_COPY(FFTLib); + + double *m_window; + float *m_input; + int m_frame_size; + int m_log2n; + FFTSetup m_setup; + DSPSplitComplex m_a; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/filter.cpp b/3rdparty/chromaprint/src/filter.cpp new file mode 100644 index 000000000..c87ae0f24 --- /dev/null +++ b/3rdparty/chromaprint/src/filter.cpp @@ -0,0 +1,47 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include +#include "filter.h" +#include "filter_utils.h" + +using namespace std; +using namespace Chromaprint; + +#define COMPARE_FUNC SubtractLog + +double Filter::Apply(IntegralImage *image, int x) const +{ + switch (m_type) { + case 0: + return Filter0(image, x, m_y, m_width, m_height, COMPARE_FUNC); + case 1: + return Filter1(image, x, m_y, m_width, m_height, COMPARE_FUNC); + case 2: + return Filter2(image, x, m_y, m_width, m_height, COMPARE_FUNC); + case 3: + return Filter3(image, x, m_y, m_width, m_height, COMPARE_FUNC); + case 4: + return Filter4(image, x, m_y, m_width, m_height, COMPARE_FUNC); + case 5: + return Filter5(image, x, m_y, m_width, m_height, COMPARE_FUNC); + } + return 0.0; +} diff --git a/3rdparty/chromaprint/src/filter.h b/3rdparty/chromaprint/src/filter.h new file mode 100644 index 000000000..33899e9d5 --- /dev/null +++ b/3rdparty/chromaprint/src/filter.h @@ -0,0 +1,67 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FILTER_H_ +#define CHROMAPRINT_FILTER_H_ + +#include +#include "integral_image.h" + +namespace Chromaprint +{ + + class Filter + { + public: + Filter(int type = 0, int y = 0, int height = 0, int width = 0) + : m_type(type), m_y(y), m_height(height), m_width(width) + {} + + double Apply(IntegralImage *image, int offset) const; + + int type() const { return m_type; } + void set_type(int type) { m_type = type; } + + int y() const { return m_y; } + void set_y(int y) { m_y = y; } + + int height() const { return m_height; } + void set_height(int height) { m_height = height; } + + int width() const { return m_width; } + void set_width(int width) { m_width = width; } + + private: + int m_type; + int m_y; + int m_height; + int m_width; + }; + + inline std::ostream &operator<<(std::ostream &stream, const Filter &f) + { + stream << "Filter(" << f.type() << ", " << f.y() << ", " + << f.height() << ", " << f.width() << ")"; + return stream; + } + +}; + +#endif diff --git a/3rdparty/chromaprint/src/filter_utils.h b/3rdparty/chromaprint/src/filter_utils.h new file mode 100644 index 000000000..99dbaf50f --- /dev/null +++ b/3rdparty/chromaprint/src/filter_utils.h @@ -0,0 +1,136 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FILTER_UTILS_H_ +#define CHROMAPRINT_FILTER_UTILS_H_ + +#include +#include "integral_image.h" +#include "utils.h" + +namespace Chromaprint +{ + + inline double Subtract(double a, double b) + { + return a - b; + } + + inline double SubtractLog(double a, double b) + { + double r = log(1.0 + a) - log(1.0 + b); + assert(!IsNaN(r)); + return r; + } + + // oooooooooooooooo + // oooooooooooooooo + // oooooooooooooooo + // oooooooooooooooo + template + double Filter0(IntegralImage *image, int x, int y, int w, int h, Comparator cmp) + { + double a = image->Area(x, y, x + w - 1, y + h - 1); + double b = 0; + return cmp(a, b); + } + + // ................ + // ................ + // oooooooooooooooo + // oooooooooooooooo + template + double Filter1(IntegralImage *image, int x, int y, int w, int h, Comparator cmp) + { + int h_2 = h / 2; + + double a = image->Area(x, y + h_2, x + w - 1, y + h - 1); + double b = image->Area(x, y, x + w - 1, y + h_2 - 1); + + return cmp(a, b); + } + + // .......ooooooooo + // .......ooooooooo + // .......ooooooooo + // .......ooooooooo + template + double Filter2(IntegralImage *image, int x, int y, int w, int h, Comparator cmp) + { + int w_2 = w / 2; + + double a = image->Area(x + w_2, y, x + w - 1, y + h - 1); + double b = image->Area(x, y, x + w_2 - 1, y + h - 1); + + return cmp(a, b); + } + + // .......ooooooooo + // .......ooooooooo + // ooooooo......... + // ooooooo......... + template + double Filter3(IntegralImage *image, int x, int y, int w, int h, Comparator cmp) + { + int w_2 = w / 2; + int h_2 = h / 2; + + double a = image->Area(x, y + h_2, x + w_2 - 1, y + h - 1) + + image->Area(x + w_2, y, x + w - 1, y + h_2 - 1); + double b = image->Area(x, y, x + w_2 -1, y + h_2 - 1) + + image->Area(x + w_2, y + h_2, x + w - 1, y + h - 1); + + return cmp(a, b); + } + + // ................ + // oooooooooooooooo + // ................ + template + double Filter4(IntegralImage *image, int x, int y, int w, int h, Comparator cmp) + { + int h_3 = h / 3; + + double a = image->Area(x, y + h_3, x + w - 1, y + 2 * h_3 - 1); + double b = image->Area(x, y, x + w - 1, y + h_3 - 1) + + image->Area(x, y + 2 * h_3, x + w - 1, y + h - 1); + + return cmp(a, b); + } + + // .....oooooo..... + // .....oooooo..... + // .....oooooo..... + // .....oooooo..... + template + double Filter5(IntegralImage *image, int x, int y, int w, int h, Comparator cmp) + { + int w_3 = w / 3; + + double a = image->Area(x + w_3, y, x + 2 * w_3 - 1, y + h - 1); + double b = image->Area(x, y, x + w_3 - 1, y + h - 1) + + image->Area(x + 2 * w_3, y, x + w - 1, y + h - 1); + + return cmp(a, b); + } + +}; + +#endif diff --git a/3rdparty/chromaprint/src/fingerprint_calculator.cpp b/3rdparty/chromaprint/src/fingerprint_calculator.cpp new file mode 100644 index 000000000..081ca50e4 --- /dev/null +++ b/3rdparty/chromaprint/src/fingerprint_calculator.cpp @@ -0,0 +1,67 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include "fingerprint_calculator.h" +#include "classifier.h" +#include "debug.h" +#include "utils.h" + +using namespace std; +using namespace Chromaprint; + +FingerprintCalculator::FingerprintCalculator(const Classifier *classifiers, int num_classifiers) + : m_classifiers(classifiers), m_num_classifiers(num_classifiers) +{ + m_max_filter_width = 0; + for (int i = 0; i < num_classifiers; i++) { + m_max_filter_width = max(m_max_filter_width, classifiers[i].filter().width()); + } + assert(m_max_filter_width > 0); +} + + +vector FingerprintCalculator::Calculate(Image *image) +{ + int length = image->NumRows() - m_max_filter_width + 1; + if (length <= 0) { + DEBUG() << "Chromaprint::FingerprintCalculator::Calculate() -- Not " + << "enough data. Image has " << image->NumRows() << " rows, " + << "needs at least " << m_max_filter_width << " rows.\n"; + return vector(); + } + IntegralImage integral_image(image); + vector fingerprint(length); + for (int i = 0; i < length; i++) { + fingerprint[i] = CalculateSubfingerprint(&integral_image, i); + } + return fingerprint; +} + +int32_t FingerprintCalculator::CalculateSubfingerprint(IntegralImage *image, int offset) +{ + uint32_t bits = 0; + for (int i = 0; i < m_num_classifiers; i++) { + //for (int i = m_num_classifiers - 1; i >= 0; i--) { + bits = (bits << 2) | GrayCode(m_classifiers[i].Classify(image, offset)); + //bits = (bits << 2) | m_classifiers[i].Classify(image, offset); + } + return UnsignedToSigned(bits); +} + diff --git a/3rdparty/chromaprint/src/fingerprint_calculator.h b/3rdparty/chromaprint/src/fingerprint_calculator.h new file mode 100644 index 000000000..7674bbb66 --- /dev/null +++ b/3rdparty/chromaprint/src/fingerprint_calculator.h @@ -0,0 +1,51 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FINGERPRINT_CALCULATOR_H_ +#define CHROMAPRINT_FINGERPRINT_CALCULATOR_H_ + +#include +#include + +namespace Chromaprint +{ + class Classifier; + class Image; + class IntegralImage; + + class FingerprintCalculator + { + public: + FingerprintCalculator(const Classifier *classifiers, int num_classifiers); + + std::vector Calculate(Image *image); + + int32_t CalculateSubfingerprint(IntegralImage *image, int offset); + + private: + const Classifier *m_classifiers; + int m_num_classifiers; + int m_max_filter_width; + }; + +}; + +#endif + diff --git a/3rdparty/chromaprint/src/fingerprint_compressor.cpp b/3rdparty/chromaprint/src/fingerprint_compressor.cpp new file mode 100644 index 000000000..2f33fd918 --- /dev/null +++ b/3rdparty/chromaprint/src/fingerprint_compressor.cpp @@ -0,0 +1,92 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include +#include "fingerprint_compressor.h" +#include "bit_string_writer.h" +#include "debug.h" +#include "utils.h" + +using namespace std; +using namespace Chromaprint; + +static const int kMaxNormalValue = 7; +static const int kNormalBits = 3; +static const int kExceptionBits = 5; + +FingerprintCompressor::FingerprintCompressor() +{ +} + +void FingerprintCompressor::ProcessSubfingerprint(uint32_t x) +{ + int bit = 1, last_bit = 0; + while (x != 0) { + if ((x & 1) != 0) { + m_bits.push_back(bit - last_bit); + last_bit = bit; + } + x >>= 1; + bit++; + } + m_bits.push_back(0); +} + +void FingerprintCompressor::WriteNormalBits() +{ + BitStringWriter writer; + for (size_t i = 0; i < m_bits.size(); i++) { + writer.Write(min(int(m_bits[i]), kMaxNormalValue), kNormalBits); + } + writer.Flush(); + m_result += writer.value(); +} + +void FingerprintCompressor::WriteExceptionBits() +{ + BitStringWriter writer; + for (size_t i = 0; i < m_bits.size(); i++) { + if (m_bits[i] >= kMaxNormalValue) { + writer.Write(int(m_bits[i]) - kMaxNormalValue, kExceptionBits); + } + } + writer.Flush(); + m_result += writer.value(); +} + +std::string FingerprintCompressor::Compress(const vector &data, int algorithm) +{ + if (data.size() > 0) { + ProcessSubfingerprint(data[0]); + for (size_t i = 1; i < data.size(); i++) { + ProcessSubfingerprint(data[i] ^ data[i - 1]); + } + } + int length = data.size(); + m_result.resize(4); + m_result[0] = algorithm & 255; + m_result[1] = (length >> 16) & 255; + m_result[2] = (length >> 8) & 255; + m_result[3] = (length ) & 255; + WriteNormalBits(); + WriteExceptionBits(); + return m_result; +} + diff --git a/3rdparty/chromaprint/src/fingerprint_compressor.h b/3rdparty/chromaprint/src/fingerprint_compressor.h new file mode 100644 index 000000000..1d93d6c47 --- /dev/null +++ b/3rdparty/chromaprint/src/fingerprint_compressor.h @@ -0,0 +1,59 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FINGERPRINT_COMPRESSOR_H_ +#define CHROMAPRINT_FINGERPRINT_COMPRESSOR_H_ + +#include +#include +#include + +namespace Chromaprint +{ + class Classifier; + class Image; + class IntegralImage; + + class FingerprintCompressor + { + public: + FingerprintCompressor(); + std::string Compress(const std::vector &fingerprint, int algorithm = 0); + + private: + + void WriteNormalBits(); + void WriteExceptionBits(); + void ProcessSubfingerprint(uint32_t); + + std::string m_result; + std::vector m_bits; + }; + + inline std::string CompressFingerprint(const std::vector &data, int algorithm = 0) + { + FingerprintCompressor compressor; + return compressor.Compress(data, algorithm); + } + +}; + +#endif + diff --git a/3rdparty/chromaprint/src/fingerprint_decompressor.cpp b/3rdparty/chromaprint/src/fingerprint_decompressor.cpp new file mode 100644 index 000000000..812b1f661 --- /dev/null +++ b/3rdparty/chromaprint/src/fingerprint_decompressor.cpp @@ -0,0 +1,99 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include "fingerprint_decompressor.h" +#include "debug.h" +#include "utils.h" + +using namespace std; +using namespace Chromaprint; + +static const int kMaxNormalValue = 7; +static const int kNormalBits = 3; +static const int kExceptionBits = 5; + +FingerprintDecompressor::FingerprintDecompressor() +{ +} + +void FingerprintDecompressor::UnpackBits() +{ + int i = 0, last_bit = 0, value = 0; + for (size_t j = 0; j < m_bits.size(); j++) { + int bit = m_bits[j]; + if (bit == 0) { + m_result[i] = (i > 0) ? value ^ m_result[i - 1] : value; + value = 0; + last_bit = 0; + i++; + continue; + } + bit += last_bit; + last_bit = bit; + value |= 1 << (bit - 1); + } +} + +void FingerprintDecompressor::ReadNormalBits(BitStringReader *reader) +{ + size_t i = 0; + while (i < m_result.size()) { + int bit = reader->Read(kNormalBits); + if (bit == 0) { + i++; + } + m_bits.push_back(bit); + } +} + +void FingerprintDecompressor::ReadExceptionBits(BitStringReader *reader) +{ + for (size_t i = 0; i < m_bits.size(); i++) { + if (m_bits[i] == kMaxNormalValue) { + m_bits[i] += reader->Read(kExceptionBits); + } + } +} + +std::vector FingerprintDecompressor::Decompress(const string &data, int *algorithm) +{ + if (algorithm) { + *algorithm = data[0]; + } + int length = + ((unsigned char)(data[1]) << 16) | + ((unsigned char)(data[2]) << 8) | + ((unsigned char)(data[3]) ); + + BitStringReader reader(data); + reader.Read(8); + reader.Read(8); + reader.Read(8); + reader.Read(8); + + m_result = vector(length, -1); + reader.Reset(); + ReadNormalBits(&reader); + reader.Reset(); + ReadExceptionBits(&reader); + UnpackBits(); + return m_result; +} + diff --git a/3rdparty/chromaprint/src/fingerprint_decompressor.h b/3rdparty/chromaprint/src/fingerprint_decompressor.h new file mode 100644 index 000000000..4e446c9ab --- /dev/null +++ b/3rdparty/chromaprint/src/fingerprint_decompressor.h @@ -0,0 +1,56 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FINGERPRINT_DECOMPRESSOR_H_ +#define CHROMAPRINT_FINGERPRINT_DECOMPRESSOR_H_ + +#include +#include +#include +#include "bit_string_reader.h" + +namespace Chromaprint +{ + class FingerprintDecompressor + { + public: + FingerprintDecompressor(); + std::vector Decompress(const std::string &fingerprint, int *algorithm = 0); + + private: + + void ReadNormalBits(BitStringReader *reader); + void ReadExceptionBits(BitStringReader *reader); + void UnpackBits(); + + std::vector m_result; + std::vector m_bits; + }; + + inline std::vector DecompressFingerprint(const std::string &data, int *algorithm = 0) + { + FingerprintDecompressor decompressor; + return decompressor.Decompress(data, algorithm); + } + +}; + +#endif + diff --git a/3rdparty/chromaprint/src/fingerprinter.cpp b/3rdparty/chromaprint/src/fingerprinter.cpp new file mode 100644 index 000000000..bab5222b7 --- /dev/null +++ b/3rdparty/chromaprint/src/fingerprinter.cpp @@ -0,0 +1,97 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include "fingerprinter.h" +#include "chroma.h" +#include "chroma_normalizer.h" +#include "chroma_filter.h" +#include "fft.h" +#include "audio_processor.h" +#include "image_builder.h" +#include "fingerprint_calculator.h" +#include "fingerprinter_configuration.h" +#include "classifier.h" +#include "utils.h" + +using namespace std; +using namespace Chromaprint; + +static const int SAMPLE_RATE = 11025; +static const int FRAME_SIZE = 4096; +static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3; +static const int MIN_FREQ = 28; +static const int MAX_FREQ = 3520; + +Fingerprinter::Fingerprinter(FingerprinterConfiguration *config) + : m_image(12) +{ + if (!config) { + config = new FingerprinterConfigurationTest1(); + } + m_image_builder = new ImageBuilder(&m_image); + m_chroma_normalizer = new ChromaNormalizer(m_image_builder); + m_chroma_filter = new ChromaFilter(config->filter_coefficients(), config->num_filter_coefficients(), m_chroma_normalizer); + m_chroma = new Chroma(MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, m_chroma_filter); + //m_chroma->set_interpolate(true); + m_fft = new FFT(FRAME_SIZE, OVERLAP, m_chroma); + m_audio_processor = new AudioProcessor(SAMPLE_RATE, m_fft); + m_fingerprint_calculator = new FingerprintCalculator(config->classifiers(), config->num_classifiers()); + m_config = config; +} + +Fingerprinter::~Fingerprinter() +{ + delete m_fingerprint_calculator; + delete m_audio_processor; + delete m_fft; + delete m_chroma; + delete m_chroma_filter; + delete m_chroma_normalizer; + delete m_image_builder; + delete m_config; +} + +bool Fingerprinter::Start(int sample_rate, int num_channels) +{ + if (!m_audio_processor->Reset(sample_rate, num_channels)) { + // FIXME save error message somewhere + return false; + } + m_fft->Reset(); + m_chroma->Reset(); + m_chroma_filter->Reset(); + m_chroma_normalizer->Reset(); + m_image = Image(12); // XXX + m_image_builder->Reset(&m_image); + return true; +} + +void Fingerprinter::Consume(short *samples, int length) +{ + assert(length >= 0); + m_audio_processor->Consume(samples, length); +} + +vector Fingerprinter::Finish() +{ + m_audio_processor->Flush(); + return m_fingerprint_calculator->Calculate(&m_image); +} + diff --git a/3rdparty/chromaprint/src/fingerprinter.h b/3rdparty/chromaprint/src/fingerprinter.h new file mode 100644 index 000000000..61f8b7a09 --- /dev/null +++ b/3rdparty/chromaprint/src/fingerprinter.h @@ -0,0 +1,78 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FINGERPRINTER_H_ +#define CHROMAPRINT_FINGERPRINTER_H_ + +#include +#include +#include "image.h" +#include "audio_consumer.h" + +namespace Chromaprint +{ + class ImageBuilder; + class IntegralImage; + class FFT; + class Chroma; + class ChromaNormalizer; + class ChromaFilter; + class AudioProcessor; + class FingerprintCalculator; + class FingerprinterConfiguration; + + class Fingerprinter : public AudioConsumer + { + public: + Fingerprinter(FingerprinterConfiguration *config = 0); + ~Fingerprinter(); + + /** + * Initialize the fingerprinting process. + */ + bool Start(int sample_rate, int num_channels); + + /** + * Process a block of raw audio data. Call this method as many times + * as you need. + */ + void Consume(short *input, int length); + + /** + * Calculate the fingerprint based on the provided audio data. + */ + std::vector Finish(); + + private: + Image m_image; + ImageBuilder *m_image_builder; + Chroma *m_chroma; + ChromaNormalizer *m_chroma_normalizer; + ChromaFilter *m_chroma_filter; + FFT *m_fft; + AudioProcessor *m_audio_processor; + FingerprintCalculator *m_fingerprint_calculator; + FingerprinterConfiguration *m_config; + }; + +}; + +#endif + diff --git a/3rdparty/chromaprint/src/fingerprinter_configuration.cpp b/3rdparty/chromaprint/src/fingerprinter_configuration.cpp new file mode 100644 index 000000000..7ae5bf93b --- /dev/null +++ b/3rdparty/chromaprint/src/fingerprinter_configuration.cpp @@ -0,0 +1,107 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include "fingerprinter_configuration.h" +#include "utils.h" + +using namespace std; +using namespace Chromaprint; + +static const int kChromaFilterSize = 5; +static const double kChromaFilterCoefficients[] = { 0.25, 0.75, 1.0, 0.75, 0.25 }; + +static const Classifier kClassifiersTest1[16] = { + Classifier(Filter(0, 0, 3, 15), Quantizer(2.10543, 2.45354, 2.69414)), + Classifier(Filter(1, 0, 4, 14), Quantizer(-0.345922, 0.0463746, 0.446251)), + Classifier(Filter(1, 4, 4, 11), Quantizer(-0.392132, 0.0291077, 0.443391)), + Classifier(Filter(3, 0, 4, 14), Quantizer(-0.192851, 0.00583535, 0.204053)), + Classifier(Filter(2, 8, 2, 4), Quantizer(-0.0771619, -0.00991999, 0.0575406)), + Classifier(Filter(5, 6, 2, 15), Quantizer(-0.710437, -0.518954, -0.330402)), + Classifier(Filter(1, 9, 2, 16), Quantizer(-0.353724, -0.0189719, 0.289768)), + Classifier(Filter(3, 4, 2, 10), Quantizer(-0.128418, -0.0285697, 0.0591791)), + Classifier(Filter(3, 9, 2, 16), Quantizer(-0.139052, -0.0228468, 0.0879723)), + Classifier(Filter(2, 1, 3, 6), Quantizer(-0.133562, 0.00669205, 0.155012)), + Classifier(Filter(3, 3, 6, 2), Quantizer(-0.0267, 0.00804829, 0.0459773)), + Classifier(Filter(2, 8, 1, 10), Quantizer(-0.0972417, 0.0152227, 0.129003)), + Classifier(Filter(3, 4, 4, 14), Quantizer(-0.141434, 0.00374515, 0.149935)), + Classifier(Filter(5, 4, 2, 15), Quantizer(-0.64035, -0.466999, -0.285493)), + Classifier(Filter(5, 9, 2, 3), Quantizer(-0.322792, -0.254258, -0.174278)), + Classifier(Filter(2, 1, 8, 4), Quantizer(-0.0741375, -0.00590933, 0.0600357)) +}; + +FingerprinterConfigurationTest1::FingerprinterConfigurationTest1() +{ + set_classifiers(kClassifiersTest1, 16); + set_filter_coefficients(kChromaFilterCoefficients, kChromaFilterSize); + set_interpolate(false); +} + +static const Classifier kClassifiersTest2[16] = { + Classifier(Filter(0, 4, 3, 15), Quantizer(1.98215, 2.35817, 2.63523)), + Classifier(Filter(4, 4, 6, 15), Quantizer(-1.03809, -0.651211, -0.282167)), + Classifier(Filter(1, 0, 4, 16), Quantizer(-0.298702, 0.119262, 0.558497)), + Classifier(Filter(3, 8, 2, 12), Quantizer(-0.105439, 0.0153946, 0.135898)), + Classifier(Filter(3, 4, 4, 8), Quantizer(-0.142891, 0.0258736, 0.200632)), + Classifier(Filter(4, 0, 3, 5), Quantizer(-0.826319, -0.590612, -0.368214)), + Classifier(Filter(1, 2, 2, 9), Quantizer(-0.557409, -0.233035, 0.0534525)), + Classifier(Filter(2, 7, 3, 4), Quantizer(-0.0646826, 0.00620476, 0.0784847)), + Classifier(Filter(2, 6, 2, 16), Quantizer(-0.192387, -0.029699, 0.215855)), + Classifier(Filter(2, 1, 3, 2), Quantizer(-0.0397818, -0.00568076, 0.0292026)), + Classifier(Filter(5, 10, 1, 15), Quantizer(-0.53823, -0.369934, -0.190235)), + Classifier(Filter(3, 6, 2, 10), Quantizer(-0.124877, 0.0296483, 0.139239)), + Classifier(Filter(2, 1, 1, 14), Quantizer(-0.101475, 0.0225617, 0.231971)), + Classifier(Filter(3, 5, 6, 4), Quantizer(-0.0799915, -0.00729616, 0.063262)), + Classifier(Filter(1, 9, 2, 12), Quantizer(-0.272556, 0.019424, 0.302559)), + Classifier(Filter(3, 4, 2, 14), Quantizer(-0.164292, -0.0321188, 0.0846339)), +}; + +FingerprinterConfigurationTest2::FingerprinterConfigurationTest2() +{ + set_classifiers(kClassifiersTest2, 16); + set_filter_coefficients(kChromaFilterCoefficients, kChromaFilterSize); + set_interpolate(false); +} + +static const Classifier kClassifiersTest3[16] = { + Classifier(Filter(0, 4, 3, 15), Quantizer(1.98215, 2.35817, 2.63523)), + Classifier(Filter(4, 4, 6, 15), Quantizer(-1.03809, -0.651211, -0.282167)), + Classifier(Filter(1, 0, 4, 16), Quantizer(-0.298702, 0.119262, 0.558497)), + Classifier(Filter(3, 8, 2, 12), Quantizer(-0.105439, 0.0153946, 0.135898)), + Classifier(Filter(3, 4, 4, 8), Quantizer(-0.142891, 0.0258736, 0.200632)), + Classifier(Filter(4, 0, 3, 5), Quantizer(-0.826319, -0.590612, -0.368214)), + Classifier(Filter(1, 2, 2, 9), Quantizer(-0.557409, -0.233035, 0.0534525)), + Classifier(Filter(2, 7, 3, 4), Quantizer(-0.0646826, 0.00620476, 0.0784847)), + Classifier(Filter(2, 6, 2, 16), Quantizer(-0.192387, -0.029699, 0.215855)), + Classifier(Filter(2, 1, 3, 2), Quantizer(-0.0397818, -0.00568076, 0.0292026)), + Classifier(Filter(5, 10, 1, 15), Quantizer(-0.53823, -0.369934, -0.190235)), + Classifier(Filter(3, 6, 2, 10), Quantizer(-0.124877, 0.0296483, 0.139239)), + Classifier(Filter(2, 1, 1, 14), Quantizer(-0.101475, 0.0225617, 0.231971)), + Classifier(Filter(3, 5, 6, 4), Quantizer(-0.0799915, -0.00729616, 0.063262)), + Classifier(Filter(1, 9, 2, 12), Quantizer(-0.272556, 0.019424, 0.302559)), + Classifier(Filter(3, 4, 2, 14), Quantizer(-0.164292, -0.0321188, 0.0846339)), +}; + +FingerprinterConfigurationTest3::FingerprinterConfigurationTest3() +{ + set_classifiers(kClassifiersTest3, 16); + set_filter_coefficients(kChromaFilterCoefficients, kChromaFilterSize); + set_interpolate(true); +} + diff --git a/3rdparty/chromaprint/src/fingerprinter_configuration.h b/3rdparty/chromaprint/src/fingerprinter_configuration.h new file mode 100644 index 000000000..69a2d3d29 --- /dev/null +++ b/3rdparty/chromaprint/src/fingerprinter_configuration.h @@ -0,0 +1,126 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_FINGERPRINTER_CONFIGURATION_H_ +#define CHROMAPRINT_FINGERPRINTER_CONFIGURATION_H_ + +#include "classifier.h" +#include "chromaprint.h" + +namespace Chromaprint +{ + class FingerprinterConfiguration + { + public: + + FingerprinterConfiguration() + : m_num_classifiers(0), m_classifiers(0) + { + } + + int num_filter_coefficients() const + { + return m_num_filter_coefficients; + } + + const double *filter_coefficients() const + { + return m_filter_coefficients; + } + + void set_filter_coefficients(const double *filter_coefficients, int size) + { + m_filter_coefficients = filter_coefficients; + m_num_filter_coefficients = size; + } + + int num_classifiers() const + { + return m_num_classifiers; + } + + const Classifier *classifiers() const + { + return m_classifiers; + } + + void set_classifiers(const Classifier *classifiers, int size) + { + m_classifiers = classifiers; + m_num_classifiers = size; + } + + bool interpolate() const + { + return m_interpolate; + } + + void set_interpolate(bool value) + { + m_interpolate = value; + } + + private: + int m_num_classifiers; + const Classifier *m_classifiers; + int m_num_filter_coefficients; + const double *m_filter_coefficients; + bool m_interpolate; + }; + + // Used for http://oxygene.sk/lukas/2010/07/introducing-chromaprint/ + // Trained on a randomly selected test data + class FingerprinterConfigurationTest1 : public FingerprinterConfiguration + { + public: + FingerprinterConfigurationTest1(); + }; + + // Trained on 60k pairs based on eMusic samples (mp3) + class FingerprinterConfigurationTest2 : public FingerprinterConfiguration + { + public: + FingerprinterConfigurationTest2(); + }; + + // Trained on 60k pairs based on eMusic samples with interpolation enabled (mp3) + class FingerprinterConfigurationTest3 : public FingerprinterConfiguration + { + public: + FingerprinterConfigurationTest3(); + }; + + inline FingerprinterConfiguration *CreateFingerprinterConfiguration(int algorithm) + { + switch (algorithm) { + case CHROMAPRINT_ALGORITHM_TEST1: + return new FingerprinterConfigurationTest1(); + case CHROMAPRINT_ALGORITHM_TEST2: + return new FingerprinterConfigurationTest2(); + case CHROMAPRINT_ALGORITHM_TEST3: + return new FingerprinterConfigurationTest3(); + } + return 0; + } + +}; + +#endif + diff --git a/3rdparty/chromaprint/src/foo.cpp b/3rdparty/chromaprint/src/foo.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/3rdparty/chromaprint/src/image.h b/3rdparty/chromaprint/src/image.h new file mode 100644 index 000000000..923da7762 --- /dev/null +++ b/3rdparty/chromaprint/src/image.h @@ -0,0 +1,74 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_IMAGE_H_ +#define CHROMAPRINT_IMAGE_H_ + +#include +#include +#include + +namespace Chromaprint +{ + + class Image + { + public: + explicit Image(int columns) : m_columns(columns) + { + } + + Image(int columns, int rows) : m_columns(columns), m_data(columns * rows) + { + } + + template + Image(int columns, Iterator first, Iterator last) : m_columns(columns), m_data(first, last) + { + } + + int NumColumns() const { return m_columns; } + int NumRows() const { return m_data.size() / m_columns; } + + void AddRow(const std::vector &row) + { + m_data.resize(m_data.size() + m_columns); + std::copy(row.begin(), row.end(), m_data.end() - m_columns); + } + + double *Row(int i) + { + assert(0 <= i && i < NumRows()); + return &m_data[m_columns * i]; + } + + double *operator[](int i) + { + return Row(i); + } + + private: + int m_columns; + std::vector m_data; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/image_builder.cpp b/3rdparty/chromaprint/src/image_builder.cpp new file mode 100644 index 000000000..97e06c6ed --- /dev/null +++ b/3rdparty/chromaprint/src/image_builder.cpp @@ -0,0 +1,43 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include +#include +#include +#include "image_builder.h" + +using namespace std; +using namespace Chromaprint; + +ImageBuilder::ImageBuilder(Image *image) + : m_image(image) +{ +} + +ImageBuilder::~ImageBuilder() +{ +} + +void ImageBuilder::Consume(std::vector &features) +{ + assert(features.size() == (size_t)m_image->NumColumns()); + m_image->AddRow(features); +} + diff --git a/3rdparty/chromaprint/src/image_builder.h b/3rdparty/chromaprint/src/image_builder.h new file mode 100644 index 000000000..2f8360b7c --- /dev/null +++ b/3rdparty/chromaprint/src/image_builder.h @@ -0,0 +1,66 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_IMAGE_BUILDER_H_ +#define CHROMAPRINT_IMAGE_BUILDER_H_ + +#include +#include "utils.h" +#include "image.h" +#include "feature_vector_consumer.h" + +namespace Chromaprint +{ + + /** + * Accepts feature vectors and builds a 2D image out of them. + */ + class ImageBuilder : public FeatureVectorConsumer + { + public: + ImageBuilder(Image *image = 0); + ~ImageBuilder(); + + void Reset(Image *image) + { + set_image(image); + } + + void Consume(std::vector &features); + + Image *image() const + { + return m_image; + } + + void set_image(Image *image) + { + m_image = image; + } + + private: + CHROMAPRINT_DISABLE_COPY(ImageBuilder); + + Image *m_image; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/integral_image.cpp b/3rdparty/chromaprint/src/integral_image.cpp new file mode 100644 index 000000000..d89cc648f --- /dev/null +++ b/3rdparty/chromaprint/src/integral_image.cpp @@ -0,0 +1,49 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include "integral_image.h" + +using namespace std; +using namespace Chromaprint; + +void IntegralImage::Transform() +{ + int num_rows = m_image->NumRows(); + int num_columns = m_image->NumColumns(); + double *current = m_image->Row(0) + 1; + double *last = m_image->Row(0); + for (int m = 1; m < num_columns; m++) { + // First column - add value on top + *current = current[0] + current[-1]; + ++current; + } + for (int n = 1; n < num_rows; n++) { + // First row - add value on left + *current = current[0] + last[0]; + ++current; + ++last; + // Add values on left, up and up-left + for (int m = 1; m < num_columns; m++) { + *current = current[0] + current[-1] + last[0] - last[-1]; + ++current; + ++last; + } + } +} diff --git a/3rdparty/chromaprint/src/integral_image.h b/3rdparty/chromaprint/src/integral_image.h new file mode 100644 index 000000000..641ec4a34 --- /dev/null +++ b/3rdparty/chromaprint/src/integral_image.h @@ -0,0 +1,87 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_INTEGRAL_IMAGE_H_ +#define CHROMAPRINT_INTEGRAL_IMAGE_H_ + +#include "image.h" + +namespace Chromaprint +{ + + /** + * Image transformation that allows us to quickly calculate the sum of + * values in a rectangular area. + * + * http://en.wikipedia.org/wiki/Summed_area_table + */ + class IntegralImage + { + public: + /** + * Construct the integral image. Note that will modify the original + * image in-place, so it will not be usable afterwards. + */ + IntegralImage(Image *image) : m_image(image) + { + Transform(); + } + + //! Number of columns in the image + int NumColumns() const { return m_image->NumColumns(); } + + //! Number of rows in the image + int NumRows() const { return m_image->NumRows(); } + + double *Row(int i) + { + return m_image->Row(i); + } + + double *operator[](int i) + { + return m_image->Row(i); + } + + double Area(int x1, int y1, int x2, int y2) + { + double area = (*m_image)[x2][y2]; + if (x1 > 0) { + area -= (*m_image)[x1-1][y2]; + if (y1 > 0) { + area += (*m_image)[x1-1][y1-1]; + } + } + if (y1 > 0) { + area -= (*m_image)[x2][y1-1]; + } + //std::cout << "Area("< +#include +#include +//#include +#include "lloyds.h" +#include + +using namespace std; + +template +T min(const vector &array) +{ + T m = array.size() ? array[0] : 0; + for (int i = 1; i < array.size(); i++) { + if (array[i] < m) { + m = array[i]; + } + } + return m; +} + +template +T max(const vector &array) +{ + T m = array.size() ? array[0] : 0; + for (int i = 1; i < array.size(); i++) { + if (array[i] > m) { + m = array[i]; + } + } + return m; +} + +inline double sqr(double a) +{ + return a * a; +} + +/*template +ostream &operator<<(ostream &stream, const vector &vec) +{ + for (int i = 0; i < vec.size(); i++) { + if (i != 0) + stream << ", "; + stream << vec[i]; + } + return stream; +}*/ + +vector lloyds(vector &sig, int len) +{ + vector x(len-1); + vector q(len); + + sort(sig.begin(), sig.end()); + + // Set initial endpoints + double sig_min = sig[0]; + double sig_max = sig[sig.size()-1]; + + // Initial parameters + for (int i = 0; i < len; i++) { + q[i] = i * (sig_max - sig_min) / (len - 1) + sig_min; + } + for (int i = 0; i < len - 1; i++) { + x[i] = (q[i] + q[i+1]) / 2; + } + + double reldist = 1.0, dist = 1.0; + double stop_criteria = max(numeric_limits::epsilon() * fabs(sig_max), 1e-7); + double iteration = 0; + while (reldist > stop_criteria) { + iteration++; + reldist = dist; + dist = 0.0; + + size_t sig_it = 0; + for (int i = 0; i < len; i++) { + double sum = 0.0; + int cnt = 0; + while (sig_it < sig.size() && (i == len - 1 || sig[sig_it] < x[i])) { + sum += sig[sig_it]; + dist += sqr(sig[sig_it] - q[i]); + ++cnt; + ++sig_it; + } + if (cnt) { + q[i] = sum / cnt; + } + else if (i == 0) { + q[i] = (sig_min + x[i]) / 2.0; + } + else if (i == len - 1) { + q[i] = (x[i-1] + sig_max) / 2.0; + } + else { + q[i] = (x[i-1] + x[i]) / 2.0; + } + } + + dist /= sig.size(); + reldist = fabs(reldist - dist); + + // Set the endpoints in between the updated quanta + for (int i = 0; i < len - 1; i++) { + x[i] = (q[i] + q[i+1]) / 2.0; + } + } + + return x; +} diff --git a/3rdparty/chromaprint/src/lloyds.h b/3rdparty/chromaprint/src/lloyds.h new file mode 100644 index 000000000..b97f75e0b --- /dev/null +++ b/3rdparty/chromaprint/src/lloyds.h @@ -0,0 +1,15 @@ +#ifndef CHROMAPRINT_EXT_LLOYDS_H_ +#define CHROMAPRINT_EXT_LLOYDS_H_ + +#include + +std::vector lloyds(std::vector &sig, int len); + +template +std::vector lloyds(Iterator first, Iterator last, int len) +{ + std::vector sig(first, last); + return lloyds(sig, len); +} + +#endif diff --git a/3rdparty/chromaprint/src/quantizer.h b/3rdparty/chromaprint/src/quantizer.h new file mode 100644 index 000000000..3bec85555 --- /dev/null +++ b/3rdparty/chromaprint/src/quantizer.h @@ -0,0 +1,76 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_QUANTIZER_H_ +#define CHROMAPRINT_QUANTIZER_H_ + +#include +#include + +namespace Chromaprint +{ + + class Quantizer + { + public: + Quantizer(double t0 = 0.0, double t1 = 0.0, double t2 = 0.0) + : m_t0(t0), m_t1(t1), m_t2(t2) + { + assert(t0 <= t1 && t1 <= t2); + } + + int Quantize(double value) const + { + if (value < m_t1) { + if (value < m_t0) { + return 0; + } + return 1; + } + else { + if (value < m_t2) { + return 2; + } + return 3; + } + } + + double t0() const { return m_t0; } + void set_t0(double t) { m_t0 = t; } + + double t1() const { return m_t1; } + void set_t1(double t) { m_t1 = t; } + + double t2() const { return m_t2; } + void set_t2(double t) { m_t2 = t; } + + private: + double m_t0, m_t1, m_t2; + }; + + inline std::ostream &operator<<(std::ostream &stream, const Quantizer &q) + { + stream << "Quantizer(" << q.t0() << ", " << q.t1() << ", " << q.t2() << ")"; + return stream; + } + +}; + +#endif diff --git a/3rdparty/chromaprint/src/silence_remover.cpp b/3rdparty/chromaprint/src/silence_remover.cpp new file mode 100644 index 000000000..af7c63e45 --- /dev/null +++ b/3rdparty/chromaprint/src/silence_remover.cpp @@ -0,0 +1,65 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include +#include +#include "debug.h" +#include "silence_remover.h" + +using namespace std; +using namespace Chromaprint; + +SilenceRemover::SilenceRemover(AudioConsumer *consumer) + : m_start(true), + m_consumer(consumer) +{ +} + +bool SilenceRemover::Reset(int sample_rate, int num_channels) +{ + if (num_channels != 1) { + DEBUG() << "Chromaprint::SilenceRemover::Reset() -- Expecting mono audio signal.\n"; + return false; + } + m_start = true; + return true; +} + +void SilenceRemover::Consume(short *input, int length) +{ + if (m_start) { + while (length) { + if (*input != 0) { + m_start = false; + break; + } + input++; + length--; + } + } + if (length) { + m_consumer->Consume(input, length); + } +} + +void SilenceRemover::Flush() +{ +} + diff --git a/3rdparty/chromaprint/src/silence_remover.h b/3rdparty/chromaprint/src/silence_remover.h new file mode 100644 index 000000000..05d87fc52 --- /dev/null +++ b/3rdparty/chromaprint/src/silence_remover.h @@ -0,0 +1,59 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_SILENCE_REMOVER_H_ +#define CHROMAPRINT_SILENCE_REMOVER_H_ + +#include "utils.h" +#include "audio_consumer.h" + +namespace Chromaprint +{ + + class SilenceRemover : public AudioConsumer + { + public: + SilenceRemover(AudioConsumer *consumer); + + AudioConsumer *consumer() const + { + return m_consumer; + } + + void set_consumer(AudioConsumer *consumer) + { + m_consumer = consumer; + } + + bool Reset(int sample_rate, int num_channels); + void Consume(short *input, int length); + void Flush(); + + private: + CHROMAPRINT_DISABLE_COPY(SilenceRemover); + + bool m_start; + AudioConsumer *m_consumer; + }; + +}; + +#endif + diff --git a/3rdparty/chromaprint/src/sox_audio_source.cpp b/3rdparty/chromaprint/src/sox_audio_source.cpp new file mode 100644 index 000000000..99a07bc51 --- /dev/null +++ b/3rdparty/chromaprint/src/sox_audio_source.cpp @@ -0,0 +1,71 @@ +#include +#include +#include "sox_audio_source.h" + +using namespace std; + +static const size_t kBufferSize = 2 * 4096; +bool SoxAudioSource::initialized_ = false; + +SoxAudioSource::SoxAudioSource(const string &file_name) + : format_(0), file_name_(file_name) +{ + if (!initialized_) { + sox_init(); + initialized_ = true; + } + buffer_ = new sox_sample_t[kBufferSize]; +} + +SoxAudioSource::~SoxAudioSource() +{ + Close(); + delete[] buffer_; +} + +bool SoxAudioSource::Open() +{ + Close(); + format_ = sox_open_read(file_name_.c_str(), NULL, NULL, NULL); + return format_ != 0; +} + +void SoxAudioSource::Close() +{ + if (format_) { + sox_close(format_); + format_ = 0; + } +} + +int SoxAudioSource::SampleRate() +{ + return static_cast(format_->signal.rate); +} + +int SoxAudioSource::Channels() +{ + return format_->signal.channels; +} + +std::size_t SoxAudioSource::Read(short *buffer, std::size_t size) +{ + size_t remaining = size; + short *ptr = buffer; + while (remaining > 0) { + size_t res = sox_read(format_, buffer_, std::min(remaining, kBufferSize)); + if (res == SOX_EOF || res == 0) { + break; + } + int clips = 0; + for (size_t i = 0; i < res; i++) { + // XXX assumes that short is 16-bit + SOX_SAMPLE_LOCALS; + *ptr++ = SOX_SAMPLE_TO_SIGNED_16BIT(buffer_[i], clips); + } + remaining -= res; + } + //cout << "read " << size - remaining << "\n"; + return size - remaining; +} + diff --git a/3rdparty/chromaprint/src/sox_audio_source.h b/3rdparty/chromaprint/src/sox_audio_source.h new file mode 100644 index 000000000..e20533480 --- /dev/null +++ b/3rdparty/chromaprint/src/sox_audio_source.h @@ -0,0 +1,29 @@ +#ifndef FP_SOX_AUDIO_SOURCE_H_ +#define FP_SOX_AUDIO_SOURCE_H_ + +extern "C" { +#include +} +#include + +class SoxAudioSource { +public: + SoxAudioSource(const std::string &file_name); + virtual ~SoxAudioSource(); + + bool Open(); + void Close(); + + virtual int SampleRate(); + virtual int Channels(); + virtual std::size_t Length() { return format_->signal.length; } + virtual std::size_t Read(short *buffer, std::size_t size); + +private: + static bool initialized_; + std::string file_name_; + sox_format_t *format_; + sox_sample_t *buffer_; +}; + +#endif diff --git a/3rdparty/chromaprint/src/spectral_centroid.cpp b/3rdparty/chromaprint/src/spectral_centroid.cpp new file mode 100644 index 000000000..5b28f5ad5 --- /dev/null +++ b/3rdparty/chromaprint/src/spectral_centroid.cpp @@ -0,0 +1,91 @@ +/* + * SpectralCentroidprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include +#include +#include "fft_frame.h" +#include "utils.h" +#include "spectral_centroid.h" + +using namespace std; +using namespace Chromaprint; + +SpectralCentroid::SpectralCentroid(int num_bands, int min_freq, int max_freq, int frame_size, int sample_rate, FeatureVectorConsumer *consumer) + : m_bands(num_bands + 1), + m_features(num_bands), + m_consumer(consumer) +{ + PrepareBands(num_bands, min_freq, max_freq, frame_size, sample_rate); +} + +SpectralCentroid::~SpectralCentroid() +{ +} + +void SpectralCentroid::PrepareBands(int num_bands, int min_freq, int max_freq, int frame_size, int sample_rate) +{ + double min_bark = FreqToBark(min_freq); + double max_bark = FreqToBark(max_freq); + double band_size = (max_bark - min_bark) / num_bands; + + int min_index = FreqToIndex(min_freq, frame_size, sample_rate); + //int max_index = FreqToIndex(max_freq, frame_size, sample_rate); + + m_bands[0] = min_index; + double prev_bark = min_bark; + + for (int i = min_index, b = 0; i < frame_size / 2; i++) { + double freq = IndexToFreq(i, frame_size, sample_rate); + double bark = FreqToBark(freq); + if (bark - prev_bark > band_size) { + b += 1; + prev_bark = bark; + m_bands[b] = i; + if (b >= num_bands) { + break; + } + } + } +} + +void SpectralCentroid::Reset() +{ +} + +void SpectralCentroid::Consume(const FFTFrame &frame) +{ + for (int i = 0; i < NumBands(); i++) { + int first = FirstIndex(i); + int last = LastIndex(i); + double numerator = 0.0; + double denominator = 0.0; + for (int j = first; j < last; j++) { + double s = frame.Energy(j); + numerator += j * s; + denominator += s; + } + double centroid = numerator / denominator; + if (centroid != centroid) + centroid = (first + last) / 2.0; // handle NaN + m_features[i] = (centroid - first) / (last - first); + } + m_consumer->Consume(m_features); +} + diff --git a/3rdparty/chromaprint/src/spectral_centroid.h b/3rdparty/chromaprint/src/spectral_centroid.h new file mode 100644 index 000000000..1c20039db --- /dev/null +++ b/3rdparty/chromaprint/src/spectral_centroid.h @@ -0,0 +1,59 @@ +/* + * SpectralCentroidprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_SPECTRAL_CENTROID_H_ +#define CHROMAPRINT_SPECTRAL_CENTROID_H_ + +#include +#include +#include "utils.h" +#include "fft_frame_consumer.h" +#include "feature_vector_consumer.h" + +namespace Chromaprint +{ + + class SpectralCentroid : public FFTFrameConsumer + { + public: + SpectralCentroid(int num_bands, int min_freq, int max_freq, int frame_size, int sample_rate, FeatureVectorConsumer *consumer); + ~SpectralCentroid(); + + void Reset(); + void Consume(const FFTFrame &frame); + + protected: + int NumBands() const { return m_bands.size() - 1; } + int FirstIndex(int band) const { return m_bands[band]; } + int LastIndex(int band) const { return m_bands[band + 1]; } + + private: + CHROMAPRINT_DISABLE_COPY(SpectralCentroid); + + void PrepareBands(int num_bands, int min_freq, int max_freq, int frame_size, int sample_rate); + + std::vector m_bands; + std::vector m_features; + FeatureVectorConsumer *m_consumer; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/spectrum.cpp b/3rdparty/chromaprint/src/spectrum.cpp new file mode 100644 index 000000000..0d47fe980 --- /dev/null +++ b/3rdparty/chromaprint/src/spectrum.cpp @@ -0,0 +1,88 @@ +/* + * Spectrumprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#include +#include +#include "fft_frame.h" +#include "utils.h" +#include "spectrum.h" + +using namespace std; +using namespace Chromaprint; + +Spectrum::Spectrum(int num_bands, int min_freq, int max_freq, int frame_size, int sample_rate, FeatureVectorConsumer *consumer) + : m_bands(num_bands + 1), + m_features(num_bands), + m_consumer(consumer) +{ + PrepareBands(num_bands, min_freq, max_freq, frame_size, sample_rate); +} + +Spectrum::~Spectrum() +{ +} + +void Spectrum::PrepareBands(int num_bands, int min_freq, int max_freq, int frame_size, int sample_rate) +{ + double min_bark = FreqToBark(min_freq); + double max_bark = FreqToBark(max_freq); + double band_size = (max_bark - min_bark) / num_bands; + + int min_index = FreqToIndex(min_freq, frame_size, sample_rate); + //int max_index = FreqToIndex(max_freq, frame_size, sample_rate); + + m_bands[0] = min_index; + double prev_bark = min_bark; + + for (int i = min_index, b = 0; i < frame_size / 2; i++) { + double freq = IndexToFreq(i, frame_size, sample_rate); + double bark = FreqToBark(freq); + if (bark - prev_bark > band_size) { + b += 1; + prev_bark = bark; + m_bands[b] = i; + if (b >= num_bands) { + break; + } + } + } +} + +void Spectrum::Reset() +{ +} + +void Spectrum::Consume(const FFTFrame &frame) +{ + for (int i = 0; i < NumBands(); i++) { + int first = FirstIndex(i); + int last = LastIndex(i); + double numerator = 0.0; + double denominator = 0.0; + for (int j = first; j < last; j++) { + double s = frame.Energy(j); + numerator += j * s; + denominator += s; + } + m_features[i] = denominator / (last - first); + } + m_consumer->Consume(m_features); +} + diff --git a/3rdparty/chromaprint/src/spectrum.h b/3rdparty/chromaprint/src/spectrum.h new file mode 100644 index 000000000..1a91a96f3 --- /dev/null +++ b/3rdparty/chromaprint/src/spectrum.h @@ -0,0 +1,59 @@ +/* + * SpectralCentroidprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_SPECTRUM_H_ +#define CHROMAPRINT_SPECTRUM_H_ + +#include +#include +#include "utils.h" +#include "fft_frame_consumer.h" +#include "feature_vector_consumer.h" + +namespace Chromaprint +{ + + class Spectrum : public FFTFrameConsumer + { + public: + Spectrum(int num_bands, int min_freq, int max_freq, int frame_size, int sample_rate, FeatureVectorConsumer *consumer); + ~Spectrum(); + + void Reset(); + void Consume(const FFTFrame &frame); + + protected: + int NumBands() const { return m_bands.size() - 1; } + int FirstIndex(int band) const { return m_bands[band]; } + int LastIndex(int band) const { return m_bands[band + 1]; } + + private: + CHROMAPRINT_DISABLE_COPY(Spectrum); + + void PrepareBands(int num_bands, int min_freq, int max_freq, int frame_size, int sample_rate); + + std::vector m_bands; + std::vector m_features; + FeatureVectorConsumer *m_consumer; + }; + +}; + +#endif diff --git a/3rdparty/chromaprint/src/utils.h b/3rdparty/chromaprint/src/utils.h new file mode 100644 index 000000000..47c6b9827 --- /dev/null +++ b/3rdparty/chromaprint/src/utils.h @@ -0,0 +1,154 @@ +/* + * Chromaprint -- Audio fingerprinting toolkit + * Copyright (C) 2010 Lukas Lalinsky + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef CHROMAPRINT_UTILS_H_ +#define CHROMAPRINT_UTILS_H_ + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include +#include +#include +#include +#include + +#ifndef HAVE_ROUND +static inline double round(double x) +{ + if (x >= 0.0) + return floor(x + 0.5); + else + return ceil(x - 0.5); +} +#endif + +#define CHROMAPRINT_DISABLE_COPY(ClassName) \ + ClassName(const ClassName &); \ + void operator=(const ClassName &); + +//#include + +namespace Chromaprint +{ + + template + void PrepareHammingWindow(RandomAccessIterator first, RandomAccessIterator last) + { + size_t i = 0, max_i = last - first - 1; + double scale = 2. * M_PI / max_i; + while (first != last) { + *first++ = 0.54 - 0.46 * cos(scale * i++); + } + } + + template + void ApplyWindow(InputIterator1 input, InputIterator2 window, OutputIterator output, int size, double scale) + { + while (size--) { + *output = *input * *window * scale; + ++input; + ++window; + ++output; + } + } + + template + typename std::iterator_traits::value_type Sum(Iterator first, Iterator last) + { + typename std::iterator_traits::value_type sum = 0; + while (first != last) { + sum += *first; + ++first; + } + return sum; + } + + template + typename std::iterator_traits::value_type EuclideanNorm(Iterator first, Iterator last) + { + typename std::iterator_traits::value_type squares = 0; + while (first != last) { + squares += *first * *first; + ++first; + } + return (squares > 0) ? sqrt(squares) : 0; + } + + template + void NormalizeVector(Iterator first, Iterator last, Func func, double threshold = 0.01) + { + double norm = func(first, last); + if (norm < threshold) { + std::fill(first, last, 0.0); + } + else { + while (first != last) { + *first /= norm; + ++first; + } + } + } + + inline int GrayCode(int i) + { + static const unsigned char CODES[] = { 0, 1, 3, 2 }; + return CODES[i]; + } + + inline double IndexToFreq(int i, int frame_size, int sample_rate) + { + return double(i) * sample_rate / frame_size; + } + + inline int FreqToIndex(double freq, int frame_size, int sample_rate) + { + return (int)round(frame_size * freq / sample_rate); + } + + inline int32_t UnsignedToSigned(uint32_t x) + { + return *((int32_t *)&x); + //return x & 0x80000000 ? x & 0x7FFFFFFF - 0x80000000 : x; + } + + template + inline bool IsNaN(T value) + { + return value != value; + } + + inline double FreqToBark(double f) + { + double z = (26.81 * f) / (1960.0 + f) - 0.53; + + if (z < 2.0) { + z = z + 0.15 * (2.0 - z); + } else if (z > 20.1) { + z = z + 0.22 * (z - 20.1); + } + + return z; + } + +}; + +#endif diff --git a/3rdparty/chromaprint/tests/CMakeLists.txt b/3rdparty/chromaprint/tests/CMakeLists.txt new file mode 100644 index 000000000..bd4b4066d --- /dev/null +++ b/3rdparty/chromaprint/tests/CMakeLists.txt @@ -0,0 +1,41 @@ +include_directories( + ${GTEST_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR}/../src +) + +set(tests_SOURCES + main.cpp + test_api.cpp + test_combined_buffer.cpp + test_utils.cpp + test_quantizer.cpp + test_filter_utils.cpp + test_integral_image.cpp + test_lloyds.cpp + test_audio_processor.cpp + test_bit_string_reader.cpp + test_bit_string_writer.cpp + test_chromaprint.cpp + test_chroma.cpp + test_chroma_filter.cpp + test_chroma_resampler.cpp + test_fingerprint_compressor.cpp + test_fingerprint_decompressor.cpp + test_fingerprint_calculator.cpp + test_filter.cpp + test_silence_remover.cpp + test_base64.cpp +) + +add_executable(all_tests ${tests_SOURCES}) +target_link_libraries(all_tests + ${GTEST_BOTH_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + chromaprint_p +) + +add_custom_target(check + ./all_tests $ENV{GTEST_FLAGS} + DEPENDS all_tests +) + diff --git a/3rdparty/chromaprint/tests/audio_buffer.h b/3rdparty/chromaprint/tests/audio_buffer.h new file mode 100644 index 000000000..165879e75 --- /dev/null +++ b/3rdparty/chromaprint/tests/audio_buffer.h @@ -0,0 +1,21 @@ +#include +#include +#include "audio_consumer.h" + +class AudioBuffer : public Chromaprint::AudioConsumer +{ +public: + void Consume(short *input, int length) + { + //cout << "AudioBuffer::Consume(" << length << ")\n"; + int last_size = m_data.size(); + //cout << "got " << input[0] << " at index " << last_size << "\n"; + m_data.resize(last_size + length); + std::copy(input, input + length, m_data.begin() + last_size); + } + + const std::vector &data() { return m_data; } + +private: + std::vector m_data; +}; diff --git a/3rdparty/chromaprint/tests/data/test_mono_11025.raw b/3rdparty/chromaprint/tests/data/test_mono_11025.raw new file mode 100644 index 0000000000000000000000000000000000000000..f6fedcd8a92771a6c070577bb3224ad8c63b0356 GIT binary patch literal 44080 zcmeF)iN8tTeSy7>g$WY0Usi=qsgfx(`OeK-1BxFd4LMjwRNu?xY zN-~7Z^St---sk)Jy?%eh^K@S4be!|~-21-Qy4JO>weEZG69oV7zyBL85C&n|vg7#w zUws@$aU6$1N|4S+s#hdGNq+XfS0(?t7GL#|{4B*QlGmje;D4`3N&7zeedy;I{XR&$ z%KtY?;P^!*NG5$`GH6e+;@=_o+C4 z&^mZNm>&EVtP55I`+}pv*TJIT%b=r=Z-bYDf8y2gfM9g+a=b4(72RTlK4$P{{CYey z{ysk8D(QpFK_+XeZVruu&Oz_svEbpLeQ>9_oQp5V*9BYR9dXOxzj$ceHE0&>k3SAB z2djeTyyr@s%j|+6n^8&zRehH+xQ=DZ1$C^eb?~4u3Ix@HLe^L(I2k`0o*@3EJ{(`5-rs z9ptMZm>d5XUy8fMgW^`f()j7Pdhl!9DV`f&j5`Ex1oxVCdE+mQd&hO+YVoD$QgkKS z7G;fF#jnL*^FqepQd~U9&J#U?!|`A7_~1}{Jo$ONIG)9ui{d%)WPa-lLoI>|tUsRR zy0Y@)Q1*B*BpB;sQZPGM>|>?hEePHTo(=j1{eucD_Atw43K|Aa2QPZvx8CW~>Qju`ymAZ#Ba`@mZK(0C#Ks z{zANq-QS9r#0$ND0;}I{7GvY?qG5YHA;=wGcFocv@g`R)#LDO5DnTnNDb7B(vC7A0 zQYq+QPWgf|L1o^`6#T@(&jd^2r-DvFmmphMEVwoPEw0EmW&LDAupZuaS;JUYJSNgM z#$$NAczh(<6wQs6Mq8tQqB8NL<~28dA1jRsmIasjzjM$ejDvBmIhd8VV3)P=hyK4Q z9v8pt`#|h$5`S}od1jU0ydGqoS@E}VPto>sd`CPyem3|X9(o7IS@}73*b=YgtB-KQ ztoRf5|2v-NwV&gaUU5AbdkZ3avRlib4`dG$J6%%ZOiYzz%c8=*#@EC9Z{Q zjKH2Znz;@SvWn#u zJhPjJqBsv9e~C*6W8|{&@#rzv%81!68tJ`wL_8j=zQkIy;$b*yS3C{JRmO&SgImnH z7jGxblpB-(DLyV6vwCoW_de!>K4SBq_&zb&2DYAp_&0plBiJoor-|fYagMkGMrjf^ z3l79zMc+o%ME()%bGs4u#94#AvOu07D|BYF{;KBlW}G)}YV5XfGoOd^1v^;$DxTRD zHHnu;yQ4f}douK|u)9?`E%E8E59Fb~4FSBXtelg`8(t^mW|+7sS3Ld%VnYXZhe7 zycOZ4!{Tj2&@;>%JRYaRHh0P-e+6IQs*CZwph(<3$|tUhvuEb`OjJ5<5s#D;$FOCs zAcIWS1=s9hkzD*1#(zd7g7Nq&OHfd5E@8ee1p_cadKvf@nWP|mH#eKB^7d&SIuA#g zMCvBvWyP#Lg4x!(6w|Mdo8zPE@x`d6I7u&q?GuGrF=<79DiQa<K#_-Xgk=*yb^}iXv z!b(-*e(^)`o#NtcC^*3SXX4VqI=^o(&Yl;8%YzdbVv%)p6K7q6CGy90!P$5}&Y2m1 zisMdDE#)xBucBk7pB~`3JZ4xKLfd2LtMNv8^*OKljo)q)8QEDV9d&TUclB^!FCP_-1SAA72;OmvhI7>UDhZwAlCn=R73NiU!$Tb&`m08efYxMu($6qbYIjpg>#` z=B8l0`qq0D+Q(tb~@`G#Bbt8#Cz_*cC3L$oUD7Qe&KKg3^BK&|-j zzhJv~Ta8^i82J%eGReLNA*3Now)5^6AbX$O(>Qp@l^&3T$A>M$^I~QQFV3NFI`HVm zXsGP^M>IToi$~9UbxXNu5dL`-=1)bZqeA#-wQO1wqI${@wSv0hq<2t7Zp{&V1tp)v zQ^n6EQSm8%P&RD)i;THHen=eVhMejwupZ7ziqc{{w>ZutUe?DaqbFdcK2};9cf+PP z8}&c-n<>Mzi9aycE7aX7Svf@{ABYF1v2bxr@FF&z!IzC?jA4}A2i{R%-X9ACT`_sP z_+(r(tPt#sdxaOnzG0DYuE^LW!<=T{!?Mihv{c8SLC_?a2j%z12crVfQ_*QrRME=6 z!?fALsxskZ{(W2w{bE+{L*!SkyI!=du)?e?T+-E#W426`$R^qSP}~AHO^ctA+m^^J zJ+a`!-d7Ck-YvFQ24Q$5_`zyBThl*mHaC7sP8t=Q{vdCiS{SFp~uzAa{ zH!ahiUkCB@+r0NZZMGx$JYEvrB~wjzy*>D08GJY5yS6NQD#{!G6P1VuvhJFAAy$5u zSIz~^!+hZzc=IxgZN|#KLC1HPt0-(%=G|L)>@sE6T?}ux%FFTOU@o6E4?Y#Oo1o>m zJkiZ>`oxu3?ksMp6MRVb)x!i=G4(dDSYs74=%%IcPzdsCQm3zDodMQ*()>P(*RsYf zSovt25;h2zyXpftBaD|t7schQ=o6a#J@#rO8vc||K9^aV!qV*+q5$NbHj~)A&zt4s zxPMSDtP%_sFJHn)h%x?!zkO!0-wG~^$bGWw2vM|6to4#HJHdZ-(U=K;-zaich^*Cd z1InmK@GP!c!Om5!s0%&S3&+ehaw-dzpo%`n{+rn^mw(+%`wtJc1-ZgnVYTpY%H<`N z-o_&XAf#-3AGJ8267LB|%f0?!TraF0o`#o^R`Cn(y-SDniSx(zh@?UM^$D%hS`2lB z_dFEFW-L)MI40h2hr_+N_D3HVX@%l2RTF>pG&dT<`h_qcs z>SD&D;jEbK^BDgfrJFy*XGx4rlMR-*%46(xRz}|F{S9!`CCa`M{BFhTS;W*fHPyv5 z-aH(ap?LC!7iqhJMyYHiwb`l?&i^`CD3@--zqhhwWfAn7YB^sxnMN7R<{hB#3f}!A zF2*mLDDu0oZBt&Thx;Gqn=`C)6BhoN4IdD7o789t%N&I9yXl;ASmb$3*VX8+s~8U8 z_d{$vRQ&a&fZDl65)FmT>|yhJ4YR(C3${|}N9loFDz!XpSBv-Zo8=^2o5bc3`gyLO zjWa@}_-M3N#@ZL(guy#&Bb0*CKci03yr{J}U1x*|eEJ0K(at=YtHghS#W;SJt!nvN zDQ@evszj0y1z(791f(hXt))yeZJwKFovD|k0!Sc=x!8eH^_hg9;f zc-0w5uSykEa?O~6xtB$E1|Q+|@x0cRHb^=R3o$?ov&$-{&cT{Hp`o;l^?Te?#dlII z*H2E|&ZZARZ+;y1h4uA~=S7v`CopnJnf4|go8Zcot?y@6?50kCQucjC?NwI1KkN#t zMN`+fAcfF9=qo>z!L=hq)0<}hw3?>3*L09wUr~XNw&r5;`Cg2-oJvY6vi7cj5(+*r zyD!xewqDJrL zfxNhM9t3WV?`45cWQ+yW)syi=Sbbi`TBn!OO@8Q)As(bbu3_`K&{SGROvRabt+$6+ zXA)EAg2ymrKlNfqT-;gKX%#oa3}@J^1~2!;^W&_tsoWlk(gSdk9cTQ3&Ca;iavr_` zyEcxmH}Yp{fu`Xl+|-gTOKS2*;#;A=2bAqrE7hWBH&G*h&@~U3K{fTnz;(5yjh)e;@E!Tvkdk z!at&YyZA2?UKg&HF-uP_P5UWms#_AZQkrn>MUi0Ln z;p(=XQJ(ni=vFEntP25lirnvVC)0X zw>w?{#r5g?9YF;>)%W3Os+C22+JL<~L)JaGs1yEbfPLD)#DCs76%O~y6K8zaS^gRj z*Ji&{l;!tux0ywr#ULZaL`j)!y}Wu;Tv*g(lgs+@_(ME2NpIi@*0?IW_Q$9nvFz`9 z2Hn&Mck5*|kM{(n!lCke6L!ofcefGIz0{B|$Z+Y+=MmgE3`6Fymb*-)=MFw*nVIxjd--h-*6VAHHE>uDqt0aWBx--usi{Og z9%Ru8*y#_9SxrQ(wWbBMN+fG`!YiwETW85Gi)q`e;Z5Nw- ze|F6~f|^#iJAMZPy&*zsQ4HteI#72eu4X+I@Ww{0+Zm_Vqjt98l0`;NV!0Au7PR8q zg2(v&wxBlU5M!b{dFpHGqmJnP2j>1XmvhmN(Ra~b(G76_A|^biyL698{?MvwW8fv! zb158l39D_SW>TR42;Ny^T_5mNo4Bdin;K13aXu#>j$z>`c&8MWEeP!!D8@kCmrv_Y zu23D^sn0Mc_%&D?XNc3mZj#rQsAKzzwr_A@B|7GMRxM1wt`c{NPPvb_Zd5PNGKWHN zRZG-l36GiMX}RM+S@xu>Ms(O-3>dRZ6*ijUI>S`+)A^^Fxz!PWi8|k)?raVf6TN1x z`R-SNw&(o|RMvdz|9!Fi5>>xLb>GtZmc^r^sZkyA-;X_)x=K2X)y7KBV(#Nb1cc;%vi-p>3 zvq+4sjT=(boAgX>743~>(KkeG20wpR6va^yb$3J6WG#3d$WD(_|7~QudLpoeSv2=u zOKiJP{&_|&oSRl`qG{Ub-G5%X+2;rRB`<#^Pi>O|5F!KV*4lkc8$ormF2f#ohstI zEM+$jQisdOSK|U<%olMtVu;+U+}x6AG#N> zKLQz>L`7yuI2upWXId0j4gaN;T2V_g)#cfE?!WjJ71BrgR7FKs(&ugm&yUfVH{psB z*s(3I^rSB*Q7`N8V4`H_$nGcYEBwc%SAwrxcNouXpeg^wNV_S}zj@#gy|v1kPg1$l z()xOb^{84<84ri^soVWHXBZZE-;B1%5F;ROI4iVw#meDpVTZ6wSR<_tzeTk(otRhAjW^#m+1i|^~;?x7U? z9OG^A?%P<|FDwWduTpuyF9^}9BT@h8pAkjZ4E*f9u+v{MXJ73I} zowubagu)a-X}A<=R(cMj<@ECbV)Xh&??*86`m+ifyhipaQ+vTh;sHpH`! z$TU^4S$%QYLw?>Oihi`1q5pD`3al*>Q`Uwh>29XQg!_FSnl# z!JE~C-!a*4`KP~{;t`zRSjJo*WrMp5`hTyf+P=cqLwV>w(VJVAT}o%4pu8@#)tgW< zKo)E2YZ>ajDW$M1*o=E~vC=sjtE#=D4zSh4&sR{|AL7RcX_bj$G81-vUgSPRHMGI@ zZ~J@-GM=!jb(ZG)2RA(~N1x^A)pE;mcK=H5t--2A*r<|TdTH#^8-@zVXxHJ!+-Y3% zvD~!6s{2y)Bh9=Wub!u@XN#R&!4ERoOSD@n=sjudt9UMh^{i&=wQ9*g99Nf(V_qs}nDkM9@Rq3caCWrw@^w81oybR&h6 z7Yat|FVr&2hI;-V+q-%a=Y1ib%ZQ@=x^t)4vjB8vq9?zna;EUadJ1g1pX9^%vC9LmQCl&Uwio{n-yGTnf+?SORljRCtswOFRI{*yWVGV zZaYdnVe^C0P+jjzROw;b?FuBktUhw)Ko@KYYqn;Yo;W-~{4i|!H2Zh3-r5-HW;t-Q z2wX2BcC*|h5jzIkBvsT=V}D`pxmYQccem@-oxyOie0R?0&;Gr~tcqAu(z85(eM$sv z&Az3*y^8eBc(MGPzIP=`tALJr!vC?0&Zc)(YdI zo3P6r$v#B1FxnsOiyF!Gv-u_)yf?y-k5IjDTg9FD&MIA;*L=~vf18jp0vHVb)w^OKCiF0{*3DAZ4q7rLzXZ?WtIDO z_`ak|cUycX9X;6`A9JNEa(X%|I1Y&?@J4C2n(oS< zjde#*!#i6#w^PCOp2hPsMexV6;{fxhVi&Eg9Pv8Nt}h~2V&dJbxK-?qlP@OYfx5=p zp>Md)&mN11%A&7Ye+tj-HbPM<@$cxz_%~|19n8EU&kmwDK9yevLfseCT|MmL+jAayq2@7^&>A_}x9;eNb!3)9kXzJ{K`TBdgd9WC7!@l2P=<2+vpG)KC zrD$)`7g*qIOKn$gfWdCS=)dvQD6eiVe{A5#6@IrKGLthjC1I{LyW9b<%~|85^F2vV z`!UsN4!a>+W!;nUATg9fP9CU-nNQznfC#H-mA7G~HSF1&H|nV2UQxZ(mFZqgW5aHk zrK;Nfh->%8|2yI9Q|oDNk7BG>6mb29I#ciS?Q*kdu8MAoAN#`eP&s)A6gI)AWyHu~ z*By^F>(fpv#PmumThqTwK~QPD{Em^b$YXnXa*LQN4&P^Z|DtTWSZ41aqi^6h=la5| z;rg(7cnl6(%SC%cNA{qWlO7LZk{2n4*KzeWABC~_KeWyp{I}H1|K_!~S^f)LR02wi zIz>}nmYU;~MAA>}&TkLd0V<<&@mDlNEtVhC?WKbA>SZo8-+cBK9_Nc0Ue|+fA2#QS zP8!`B48b$`WbkKsrh+;usitNa^(3{{4d1^EITggxaNUVfxO^e|^~QdEVBs^bxEfW% zrgO|TiICIk?FU$Lw>dn=0>1?>#oMFiIICz{v@fy3NSClYKKslGv}H~&9JW(B1=dIK z?Oy9UWK}$Q!%KTWrYbd?h$eK`B_u7R6n_(wULtD?|dr55!Q95n)Z5Uk#55+9j*FS zE2w5G_&iJS3 z)#xeXXB8pusfVAzBmsmju_tiEsksZVvPKoxI7oVh51V72cvUnz+N`%yL|0ivimUZ> z#suCgip!hGyBF!m&blrOa7G=go^8$vMmJ&jJ889c7&Pf|HDdLuur~_Rz9lYyl@|-9 z>HqN{M_L-pW9AcBcTg`dEw2Ka-1U8Lx<0 z*2kJ-jhxphxJBVgig-0$TF|I3;eeL-`!prc#JZ9bNJsp}{-HgP0=#iigq6g@#aQ+X z-*tkQo?>=!P%%6qtIdUuGjh-<8M}{Mv4F1YU@rA!+xKPL*YIW!Bd-_HOIf_RoO_&4 zmpR*T5_43d8;|4bVbP0DAiRUk#suZVf_DDahu?>NoWx7^hwc*>dGXKbs4(p|jlyj$ zbB_{1*=2~m@m;)F+bO;wdJ=b&Uq-LaUyFpKNRQj{VI{hRBL(>JR0&ku+9&-GZWMwi~?P@r&wbOUuL3H-_^f( z#7ALdT8zKJ2;Gs$E*H3>U5?vi3`A7Eu zoFDq|SV4+qsfaugzw0XBS>-ZS+94d#nH^g5-J1|xA0i%xrX@}(M8PFzh9>I&lwh&S zbkcSVJx67lsE3v+yoI=alB`jTb-s0ayM5R$Ois}T;qM|XFQ2t^QlXEkGrK5Xtip)p z;N5W5EkH_r$k8+I^_MRQS@sxNnO~Fh3|!xD|qz0Seb-@Ue*hHLbmP6TK%p5 zd7n?f?<&7 zq@zz?X??ME)G1xQAmv)N)Dan;4?ACbC-^F?b@i{SccvSezEkSZbj>oPq$?hezxv_j ztrxppns6nIUre2qzD)W<>8hri5neLR4(9+@MKe|R_L}*wTJ*}b>!P(*Uomc#av=3s zN|e$drAj>S>Y%IruQj@s>uMOyjXyNoXM)vu>W|<;*fnKP%AC})sT0Bn!`#6;*EU_L zbLH79ov(fnb)>Z0q~uI}KIQIk2BbJW6*LS>21B9(;^Ee)`L%u5PDbBEP2vGzrqq_H z@1{;qU7s=~tRF0o#$T&(ZR)im&fRx_r0?N(PV`pvFZ*te{|WbntHLE=MLV)T>RWb- z)|vIg(Zr~QY+j8={($jF-{(Y7O*g$wRtOwRP7X;GIWcb3oWB z+=BhC+NU^7|CSC~i|49vmsdUaJTJdV2W|{{g?p&)5fsWVYP}a^oukgAGz(f%W$rps#|+E4sXRlGIY8>PqZN3rX8ow2j}P#KM0E}SV&j=+6qjMfEHbcla< zB^73HXZT9^h4UpPDT|%aj;I>W=q|^6;I!Jy>ZQHb^`|QAE#)S*YNXnfSzjwW;{4C(sGll$Q&iTw`}QKLVq9)$ljkp?KJ?^HBC%g2P7P?>+I0!E0)op7Qx1Y(GK1u1Zb4!(*TD#{~@9 zEc^`XyoP?YO59nJWw2_~893bWMK>tx4Q zDd_j*gx@e@OS7%U5}PQ?i%r;f?6P>U7IQ*;3XfgQBVtI{x4+j zy(;3jS#2Z64Xu2tj`b(9NpcUv4B5Jx>nCSxo2wpA>og7V-Zdg*Eaf<#m1Foj$+}W+EhIh-P?QL>W;fd4Pl$C*mGd|>Px zD%Z+hwLQ2o97P!x4sXHQ&bQMDgW+bcS)ZbL3#eO$(gnjJd>Qk-9b|?HS^hOn3^h(DtLbi1$JIUCA-6=WZEQ$ zjP(Ee)er;ld~(N32Pmw^--~oNw~PB$lyGwQ&^2AVr}ZSB@anGeMs|IZT}IpG>US6| zy9{v~1(r$!ex?)jC)G8FuIea0_Qw0|4>qONPP0c-5!pxVyzF#TQ8m#7Gq0wfmd~zc z8UKC@_Yb76l6zLNrq!>_^k^^1hRIzmV`#B-^4LnM{WkfoyN<#icIm&c7oR`e3FqtS zqq{}ZWxmTyeQuzUt}{;gw9_=V>M^X6TS^5lsB^Q5%>~$FxSg})L{fG=kMA(RUc9i3 zu8Ewxc^py-L-9|3)60%id8b#BoxGh{OkGmL-b+0+<)tW?5cbEJ zyT$AzR~r=dh+0M`qKsCX6W-Rj_F0-T2L)47T{;_6p1{*Di=_>C?`5632SwL;wf;Pn z$yll)Yg%XO0sqcy%$amiDSpdDF;{iXO|;ExqPK!tb16m{uNqmYb}Ags4O@rJbioFP z8J!_ac974p$X3=IWW@I&H`&YFr(R4?FO9`xkJ=d=;uOuy_*07 z%b91ewDcs{n~tg=Qn>#6{ONiON7%Dh8Pdcx;JDyGi5jXkk{9A#yx4@KJR z?ufWa58xTOZ8m>h3JQjwQ-BxMPmAH;7o7Nj`EJI3?iir<`spk!6?tW-t7j>t z5Pdgo`vy%p6aLa!@hocePO~ga!EV(7RduI~VLE=Ni7}{oYBPO6hjM3k9*$%g(Rt##QBY zpx3E0n`7K>u)`)D@%HlCqqJO#6QPw^{+6`v$zU_Pk)Lu=mnCHM)2a1_tbI;gp0K8}UenrsrIVrFQORyaonQtoZ3-KMy)qq3 z&BL|HF7sNf_9egHjjQKi>kDG302>ub>pXPB%@4}_%XNCHLc)Vi&-C!!2`ikWW?ts& z_~>S@j+~=-pQn?(>G$*wukqiXR=5Bfz`Jtfi~7X zORgJ7S&W0dbu{w>STdt3dAg6+jW&Vx=6l^*mC-2sd^z;h%E4}aESBh``>j2_7`X{P zPsu#F*a;7*$bO)~YC_%|cKI15Ucsm@sQC`jAuVyt?QFBfoki8f>pJs~U44^Xy79q% zm@y;X{8&6bgAe*ZSt?8?XLY)Z^?GpDM_kQNN413NhjcN9+Ot{>JL{?D{G$7M^T}-W zH{sjS*#87AxSZ~ql-7IdBJ00y=8YjHg9>bcK3Vl(AtcU&7f!W>_^-0x~{QPqo<1Sau;HpVwomG$JE~{?9pOa|e>h1%q zjhdhmeFY}?Zq*OsOhV~pm7@m{+=Ze!e#Nra@S*2U`qw6R8_$BzNBfhu~ zMxWrOR`7gP9XE80ZQAc$$wk^Q-?fm=$`C&4zCe{8?_|J!T zuBtmfFlrarYsTM+k~yXev6iKW>xDVX0V#i|+n@ITRjT`n;nHw2ZtiAo%Q3=Y*xBH9 ze>vfiQH?N3p2j24Ubn>gmTkhGFJG#_#wm7heB^j#`&iJ&eJ3ZADyPzIj__cul;{ zm)Tc)iUV9j51Sw=Yz`edMAe z9xgd~lAK|h=DG)rwqM}+yd6UMHD9|Ru;njV4m6H`k%#bK=PmQ`w*P$rF_OJ$7GtXM9>^| zA1t$tN}FX)U6}_Ueh_O<EMo{g1b>uqg0EZVYlSG>J5-P55r7?l40KSirTBB9m3n;XbvlGqRWa{eLH%# z5(|E9bwhB>WUoKq{6Z&vh+XtrSv|Z$VfpYXHb1T>^|6S#HE2l9RQCSA@YqZ?N$%rl zX|FIjHGPv@{=1+5LT4sVPxwzp`pk-_v;D7PZ;REmH;?3m?OpJ3gl~&OK!3cx)EYil zoo;lUyJX$Gs-pr_#J@cFrWLoAg$v`r8}wst^oshf(!pF;%0NMQvpdGVmJ`#-DxK7R zqp6v}EWJZqo|RY1V1Z6DNP^e-2?v>1x-{GuHlHBFkJvkOg;?3_L!chj@9=AUrX&D!r^w~kP_llJL``I}?Y zn{o8l?68C1n!?h9eA*YX4yaMjLhCMg{T-51R5sP+rILPIgsxaZYqrD!uVVkHIH#Wc zm)v93MZNv9v2TXIKY1$`m2wxmRY{9Y=fp6~N5Rcua+>*&zRY~taI#F-NKc@)^X{KV zS<*6D(zz+gQcLK8^E|&)hp|j@&**JtmFy_~=stnhp{9%{gB*_cQL+PBH`RQS)8tb_E&LKT(eOXv>4W-zFLiiL<9+7VnjsBfjXhB`q zmZj45ZoW?(>LQ48cW7M5R^f-T2L4LxwMcASg|K?=Bs#Y-q z5|TR~ZZL<2e71oe+-RMDiM`Eiw_APli54p%3YS9JwJ5u48+me)uNg$u8?07N2IvZ@9w=eQLpiKaxZEFkSdGMk^rBH;Iz(g8_D6 z>#)oXKJI0S9V(QV8c7#^NuxFpCx2nq*Iefa6;yr946A#qHV97a?f1zc8+IhO{SJbS^vDPAMc~;y# zDJ#$A`HH;W9edox3#ZgNMe%ATYrHD2eQA9!;MFDcV{#8jXBw)7S5)DFd6E4R_aNny z5w16Wa-YkGMyeveB~O}om39Ay{EuCw3k)`Q_2&G0pGtPNSq# zF|7aYwHL)>0oHGC<^|yBCa-QQHVXN7((Rj1=hje)7;Adg-nuyrQx@Vn;f73H~HhYdiqDflw*WGM4UbGaj_KQ$>8S5R! zIYrp8Fh88eHb-Tq@;JYm*<8VENsU;=8LS!3dT)_SM!EJ?$k|8jC-+xO6mQR1<4l;@ zfol^4&k&buse(_j+mC#inM(Qry8G)@bc+{68O?W-btKQ``IIJ1p_*5@S}ph4_IK@v zDgIeLr;5C#&ffg&|6}wxpG?a%uR{I5o>SB^e21<+D>qf=(T2R-h_;(6D!a>3t&BZG zp4?zoMd4x;)|tuweZ}t-`&Em0;ukDjf$!{}h@iJc;!bLDBCkzh&B)Ix$f`YX(UWxJ z45K{l-&G;)ccUh&Jx-$?XP-8%l{}&5bNu~;NWCn=Z-ni>K6|L6=V6p0{JBF$>)~WU zd7Yo__ED?h^saLJc(vRCbMMBgwVV@K5)Hzyb&Ro<#b4588Gr$1o7E+{@E|{D$D7ZK z@Q7*om*ApV=dr02EtMAe#8z{}A(Q014jkYXdgv?9({#c+0Jim!*2Gz|H4&eY3bytVB^fG zjI(ojslMve;_t>QWyA_>u{7;om9h5J1NW8xK;=Av!3xrTKeP2{71^C4sF~fC`+fHC z{>FNS&zgC1|Lu=Zw-=tPpWcq%T}3Sz9H_(E`wy{wf49n zc|yt4J|5${v9Q%hjw%(rZC9w6$azcNxJO+x3tF8O79Ytumz*?88Jt#u>P~N-+i_VZ zOzU1nHW>|X3HwxF|Bhny6P^7ozSh+#8^O~*n14>=+~%V&yPB&SMoh ztz!`1KM$Q3}*%efVF%@(QP+Q;jt;^gTm3B%8ahXs87Jr*7xA97MBxd*z9<5GJ01&ovl-@cMguy z(YF85+<)leCZp76iA_Ad-S>aWag88-C{B67N;Y~=4}FINdd7$Rf1d0((oc#RH4mmf zV!RW)ou4J=$~${#iCZbE55(TvVk@~vIe?ez^<~G|Cs-)rr>aBt;))ei!4TJ}s~eH* z{=Z7qJ>_SsAU}sZeKQn$(w2AK6})_Pu}eI05=IeEB-Snh4K9wO>9oI8;%@8hwWVz4Z3C@JRlLqP%G zonq}q^hpsud0*T#w98$HPhN+o-|3B;sJgZ8-PvJRV3Yri5Ry5%@ITC8*0lAa_ELbQ|BT6#-cx?@NAI1o0E_lP9zJ{^UBiXJ)`-D`T$X<4aav7rWgh_V0)PfKBd!z}u`ml`dH>c3!jMJ81Uq z@YNW{l~ME8wcZ=txx0_9eke^@Weo>Hc!BUe`ga0P{w><)u=}H8t*Pvk++j6Pe9ua= zYd)Nk-@e^TviuVJ{Y~wZPLfgfre(ypA>(Bz>?=-Yq~)aK-l0=e-w)zDd9KBeVsaS; zvz%9E_;|^DkLn^$VwwNgtpUUqmq&kPp#<;WQdY^m9vk2$;rT2)f4_Amr{K!S8g*f6 z7LBw`KK)L;G1MK`6V2yW@BU1$U^1m~EX^)VWV$quH*V>_+@-zNwI! zk1tp9>9cTM9;e+D7O<;T(@wxDx_GH|Ev7({XIXp)b@|2IlhF7W54u;Bt&)!U7AxKm z_b|Jxc9TY{>rcYni}K7ZUftAt8p>_oQ^2#Ffvd>=OK?_lk|KHH)&#m~FeQ=Pwey=U zcxC4u8dFM5Jf-b9`e^{B8jk0hz)xP-DaHQI=bKG>_(<-jxKBPz&LiIBqau5k&;dAP zeJe#%9TA)*XoWZLcaFJ}82+2`DGwXvy($A+F7WXVwfZ8zG%=U)-nRp4%ggXNA+!;` zTd5*_QjROF0(WMWDo^rbI_te=1V{+v;?3+Bxv7otBH^0VS+ng47*Y~%` zH4StD&cvBj@a0v9pR@2juiwvuhva}Sbh3{7$@k{;0%RvWl*jlt;FC5o=5rLtbSLQA z(SO6R@(OleuQJJoi_XK)C~TB;*t3hiV$k;x?)?vU=fv$t;OGwat$;7Hr}b5;veinl zIUjSkw89)=Q)g?FJFja)ck;}yY4XHB>D*UE+v{fhE8H)md+t;- z?Tz=kt9BFb_EOuX59h&Q3hcZ{bH9wQ##vM1_s^}cuztgMDyxat)MAw?So39x};pojSaIq{n0k6T!FAAUIOcPTKIVs$U4RTXuONI^jJW-(gV z6<-tkB`J*IaQHjU_{)rvyL2=AZ421@OGY?ut!Kq~@|?;@eu=2Q<2-am7j%rCfph+@ z|DGIJz*&MFkd<_-8{_r@UezVI!<{!H#QSgJc!iAeh?x)KxgT(TDO#)}&Ho7N$3fk& z47R|asY7ye&@&aB~6 zs)FR4>mRxSH;C&eD3eSWJE=myqm(C`$$a@_saQ;Eq(=PKQq(0+Uaski9ayH2X!#W@ zWROQcgqdH(Tt6(6bc`19RdS9#EBrLnLu=$S>76vR_N2}z1evkS@RAO0Zz?_m^zTy3 z4L8dM@_Mo}@}8ZmP#^w#&nYXeFZrgC2c@a_ck$AHEal#M2uzgIfwa!uXJ*)q0=y8^ z3hR3Y)>>JmzJ6%3OZ61?=s|7u#V5%V8fu$y@OYCbg_(ou%^g@Fw^_Yt z{PTYMvn=_7ewzE~qraRwX(h^%`;Kqdxmu{Mnyi9*n9Vois{HmT7JHuHjkNMCmBX*D zJdt;P(kUv7BO3UcL|a|xZ3QXad~M1qhnyto#IyCq#GUMPja>`r)9e!G$MIrY7#n8X zx3Omgcgfj+7cj`nF!iaA4g7af7dmE--JKP9KH%E|&|)A-@C5lWf+Zq_J9yRDS{CyS38WxT~K zFrOEbJLHqQF5WhyuKMLp=U`iX46A#_uGFizq_VkeQxEL-^F&>x)5o7DUrw@`fmS)f z@2PchHg;%$mi+lZhckeVv?lcz~MfsfkJ)cNR@RkDF+BkG+w(PF2f zE>z6K)-}wdy8YFLPFSrla`OD3W_~-|yBqu3A5M}z&pP}$O?3Zc=J$%Bk+57E1_xk> zL~G{60{@wDD&@Txh90HAYdDEioEjSL_Z6(KFJ64b_>1Mz^ZE&|B=>?)n%}|hCX88& zJqxkHUaB(L%gK)!F2G-+)T@})|DKEI(~fJ!bv>BH1(4buBGN-{PdTWDypciY z^ha54mFr&=P3vTsa;g(MG#I57Haah36fx3h`->GI>Q7zlhn@ARtFE6c<38w=M8D*m zqT0U(-7(Ir9@abjkcPMiuO-h-ID=7EV!uD|%n26$QD1q1@!T06c>SV+;IbwD$8nd=%a`W8~JXF;2bQOD+43*`AOOd$Po5R7RPw zZW>;byKKLQg7a$kW5x_I%|>z2g5O%=hLKR2-2GqCRY#i7JZJMZ>J3hXhX!zW#LVW= zF>|TpKDhiHv2%sZtBH{;Y1!lo<@mjkS3&IwOfy6bweWPgrn1u4qPx24{5V!#hZ~3D zfUXceR5lq-_sqqO<>ioaFp@l(^=?>DA05Jga&^wAIeQ=lu4ae6b4abQZnI z6N8d$aL#^bX6U@z$$&YK*o;?`d)p4-zvR43In`0}?CuR1aArz| zz)9C#(TeDkXtZZL?swPOCi^)bM8n*ja`4)bYx}RQy;dq38a)v`7k%yNFq?GccSen| z>>B5C-|}p&C$Y;x4Dc{UXhZ=t)3vSQ`yPD2xBRe?);vkoCC@l6ZMDOFOvDNUsG7%d zz!zAh5IpRSUZxOw*mv0Jw0AH2+8>JbhN{#DVI_G6MRHcSs#OhU^{;v5YuR-mRP}_Z zcRl&(1*6n=I;^Vmk|o0|;dx{I=mdTacL`<-Gr-q3Y?tiCCq0CRvF3xUUeo*Efc+`> z>a5cuPX_tI#aMToYqd~ItT*NuznkeAGvl6tBdwGUKZc)@nJP1 zmvK);bDHA~wOt#0`!atde{bVs^>-iG?IGftc$!nGa5IFz4he&>)^pf8IsY*hHj}-l z%;I||4N)7Lm9c+4+1*wzu=)(WgRpD*Wr)a3o}qP=A3N%W@9{S`CR%$g+%hR@7j=cPxzSfp z^k02i2NHbzOU=@3UrOL?ho+c1p5RJV6EgC z!^ugvP#hMgR-TlZr@5cOZskhj5Zk9512ZMvCZ8>epi`sW~c#LH03b$#P%8ZPE{| z$@8~CXdT{}s1ugxf}`%%ZKt|SbZc_&t*!}-s05nNBZW+tuTu-37+>Z26yNY0L4!4{+RC>o}n z$gJqS8&m)Vwr#l|{A@L!}g z>9Zv3stU1>)2A83+M;(I?_6Zz5h~tw;xJK5m!bGtTt4hbo5b#IxRs6m;QI;YFbB4l z!q`TYe{6l1>FW|!ciwNa@y!QNJW|X@Fw-3$wQwf$u=_a6@xoxatOD&fNnT%xag*nD z73GWM-s{>>-4z}#7-78ntp}X9gq}edZY1A74`FNhBk5eXmZz$#0>7lClJ0BrB;HEU zv(Rg{xo7ETe)z|_wqmrG>>b6b;U%=u0^ePwbXL&II=dfRL-LoAl72yQ2UL=?lfNwU6#ut?&-8YpPRc#k zndK-PFitL=Digd3;T6K<$%;EM^4Gc_NqxB7K8NRT*xPE$=gIxnYem>npWA$w>=l3J zdYkxnp^x{m)e`-a4|SV=VDA$;4j1LuJ1K!gm3{~{A4IK0U<;>`Ur6)S4Cw316IGm= zY)@y6Rc9srj+@Oolh38N<7Kb)R1J#$6@B}M&8aUXbP8+To2F@#C-EmwU;W)&-j!YN zwikOmx*lIn2BUn z{;o-7uPTlW@28{k;?GecaE+RBlpXU{?E5Nx*#b)5h3@Aln&(v=$64b!7@Glc%lRE(Z4nL&Lvxo{Of;36suIe=&Fuef@_D zDS)WtoM%_>e_I?kmm!jq)MZ3ZA6fFZv^!#wzj?8rf8OPj{yw`|Rabaft}Z&xkL9ea z1Jr(rV=6lLJT3ajJ&KE?wixGaJ4ubqOipuNb8VE%zEgI4D%Ztd({1^EpUQe4;K(8J z!3^lx$yV!ViRE%Z@_i=Cq(9Vk)D4(qjKXS#P(?o-0^e}*VwQ^Lrzl1AeWx4L+-tXE zm{`=o-nB>g%#fM{H4!f19zuNF0)|Ol7&` zbCI$azb8*`^;fWTTXu=oBP#t;^lmky?@a4N4&(9iaPq(BvK@Bbc`vT`9ZSBCReE5| z_?s4SN~&vvK9^>pufo7H>ydtrN{@+NoxKSd4bZBZI_*zeB*&t1eVRTn3J6QZBYSBgjK8Fz?(ZSpw-=Gyri742Ypqb_ShDrKvjyy`d2Fz$C)u^YT4r#UN!KS1!a zPDdQ0wcqw#dm~i9lp9<#>8>TpzZ)i9;Z*ntcMB~JMu$7XZ^9SDU(BJUZs>fk+YF%( z7d69eU92+c zkhjI~wBouv>KpazoQYPVv;0DIZhcy~Qij<@lH4{?WgY%Xdt71an0`5?2ZXEGn3i|)a{Tb(3*-F>wY8*NfOdeXIA+MXi#IQk(+e7(PyRDdzIf zEw1)A9ax1&lGwToW0}%AUaz`8J-MIsX%_6wCJjZ>dhGBmw0S(>|UX7opC4=o)s+@aa2S9Pw=t;V{OGh*HL9h z)$o5~y?1Ee(GW3-E*OL9vp~jAuDb-oCuj1`1|97vM_zSI#r?1@IaPwo-{Xhmgi;3V zwabptQg!r=ESuTR@vr=Jf%>^gwkhxT$EjY=*7Caut8|5vTdk_C*Ia?HjqX-_EqdJ7 zOHm%Zx2&QddF2n#`MLTl*`FLG19auxoa)|ll-GYzC+n!mUS%+!9zK4$YVUHPEb6?k z=VT3+ITp$*gXD=?_AF}Sr*wSfe6s2_pFQ^m5Sd4=e;hvl!q+$ArERo8lkg2{b{Q`> z6L~jbueMakm;9Cd6^NsDk~{hR0o}Re8Adm#BBzRwZ1mVc`uh-@c^-+=CXdOBhdswR zxxae=>>Q*%{+7pP`0S?Ayw@u_;D^yk{Yk}sMUiZcTHwiFS!RfsdNSH`t#gz&dM5hH z+@?^DH;M8;;AINN{RaOO)owCr_>&Ak1_Y}z2>** zk~;`foipiar{`jnPlt6dMy(p&nDQmYz6cd9!l~hrux3iVl!__YQ&Lm@@$8@j;r4KP z7^Y-OdBbxT{!Do~^+d{^l#;29QU|BDN)1zUrKV54m{Kpbw}0K@ySXW|Q?{p6NFAN} zPwK#QUDLgu`ey16DPuk7BTT7~QaI{fM#SBqbra^;3AWv~2q`OM{yubjTJ@#_88?zmd`>ibt# zUv73Ky8PVb9#^_v{ru|NSF2ntd-cXEe_S4Q^{uP_TzULzt!w{YJ9zEf)w5T6UU~e= zsH=}eQG9dwf}U8j=+>(PF4wwL_|m3J*IgNO<^1JauAINp{A#gl<=xeiGo@4NrgZz# z|DJwtx<#q0Q!=EEPWMTM%9*oet&(+frbp5(h}&E_b7B7Z@6VUL@ZyC67iym$cdp^N zspn5#zBlfZT0PUS%-b`iWceyvubj^-!mM@0uO z%sqYn#Fpb{kH2v8vs3L(&pxyC+=PoIuJ#QYrf-&ce75&;tk0D{-@t+o6l|MsUan(V zS7#cYaiGGhTDIC*4`(bBesporse;EE9I144aB( zxc|h8lU2^PxV$o~p0QKb+Bxgzc`k3>e68|UxbCIgdvjLG*)hkOtc^2WNa=L>gH!7c zcimfMSMNV}Zhms}=FN9*ePY|O9rOP_@o#VO=)++3kgg|cOL6<<-XNbWINM`b#jv3sWe8H=Tx5xsZ5|M8ZGw;XJC z`0CM)r>9+5d8I%+J!O1`vsqrvb$9+|*Y7F5uS~Xz7biGH-V^23eKkIV4)Dqct<^HI^`l6>x%qZQW z^v5L*-SFh~9~68%|G2#Wr=+utZsY3Kux3Of7%|J1*#U={8fIor8fJ8`X%Yw8G|(_N z%+zq=Fg8uYP%~R#F-s$9G@yI>-5>VyTCzRT;j{PqygO4i2))6ki3Wl0wwE>Hikz~! zWrHgIt?E_V*qm(J=aEL%)7e~!NFtLeud7p&mZY7}Sd*S^c&^fm^N>cYwJ;!|$o$yY zzysUUcy5R!jM`Z@h* z`u!xWY$kg!9`pC~40N?~Mr>kJ`!eU3KmWe(9+8Z?GnFU2;R^IWZR+-E5tR3r&mS5_|+P8Y{g@(lUB#yC8@;i!t6nTV?_|td< zZFGi5)RQwzzVYcUW6n~RHQWa?C=*Jn_ zrfJgqr3}??($FfUdYgu+gLR+OhvgH|ZJf5yHL4d0Q61>9AcNQ(`WZgP%H?hpuq4|R z>ogMm-eh;`#tcs8i1b6r?bS`>6_N&$=dxW&fyyV(7XOHJga!~7qt%gdvH5X~2$IvO zL)0u<4^3k4<|T=8<0wjtIxx+(P5v($FQ z_^5JWIa--gGt_je?x6jVvzz<52lHn{29Y7-LKpR zZ)e{i-)qlHXNql#Ww$xQ($%`yIm??F)J2@pPWTPtYND3?N$|TQLkVeasCfzjI){}* zeT(Hq^J9O43HU5)5|RRXu1LL0e=BLJcDAfPQlFk3^#+>+Z-o0rzC;Fwdw9Frqvq!( zk!7g0tE*iA#*$*|W2>=#;Rdl~j4AwCig1!JO`kGVJyo!oo*n+#`@(JUjP>PuD;$V< zY{lrJ^nwP31IjwrKD9izF0|dTZE|qD8?gF`rAWG@yYiU|QmeG)r01yzGR|c-&S;xT zC+|!iky4zVl0B_ndbTV*JL#orv23&0Dn2hgB|EQpru?ett!Sd0pl+|@8BV1k8Iv;# zGahF2PH&rXPgkqVl;ucPNJh)}iq?uZ(*43Q?4wlQs5yAwAMkDRRry|cx4LJ#;*Jf@ zeDCq#)9{GsviK^p8-c`ppkZU@M@-3 zbE_RyBWs?S6^=QcWx@Tikz|}KBCuExI}(;*Z=sKFT`Q3B5A(aB zr$v>b@uJs)x!iL2Xre29k;+RvfG042g%$7y_%3q>M}q|45D|&|dayfl2a%VzNr1f@L-Q=dcZ&s_N)n$TnzIhwpvcz_(9hC^)ms$1q;cUCPClcCa74di(=b)U7I__+ zj!g+Eg5v`t0}De9qEezAtpO+XhYSoF$ByzsBBOk@Dpfg3+EZxaE@fs?!dOly#ariM zxt6+idQS$|VU7qHslpD0u;9;;Gx6h8Cx#Vj5Be?y`ffD8ooIphmS~JnkBo=q#L-Z- z=V#}0$3s_r-^pN2C_8jEcr);~|GVE7_yOx3-%IPD8z7>-9Xx*w=euyE3{w5A{;0Yq za|z}#>l0a6dax|eK2#FsW1~a6{cO)>X9MRs*Gq4oFiMO8dF0Q8Aznq?f?n}^DeD;; zr?*O7qP-`XiCkq|!Z(GQcpo~FttZTR-!fV^HZH ztM96>X*O!!tHa8GtU|(&-ja7w*J%&x9ZC0+Rmlr=O;z)xd8l15LpV<~M>;@$O4d)j zkGC225UJ5A;aQ#*yPxJld?e7_#ne2{8 z599&Y#!W*0;6CN(*dv)=VTy^fMF=98i%vl){xEJKa|ARB!~&BJBpc-e8CmuBDW1shi;d=k@_W@Mbp4(*Ug#5p1};j_2Ic7 z`U=xiXcesGz7ZD7e$+(um-I7qHtk+@j`F^&2JOXtz}Q5l6Lw-8{eUqRYQShhU5^!q zw}#$_E21~!6Ulu5a;n6Q@qGFyvjO)xZwbFY*A0!K>c{s---Vk8^q%960$WS_F{jMu z2uY)BViTgX!b5@+g6+asWF)>l{xH5P?vC@w7IZaa0(Za*@LNW2x{Rb>tR@Q(@S$DR>a$Z13ad{t~nyoy=@d6L|UCI!lfs?h^Ir8pbDhJ(Gkd z!jvCURQjjjz-JS(ECrY#i4H-<*&H%fiaT<3fu<%OZp0S&1xo zI6MkALqTXGs}HY*__(~a(j-5RqMRydS>g|nZ{*zwPdAe?0P2-B1@}4y( zY-cme$+(T8Hk8^-p>%874`q3qE}9MK>UvK(RY>xnDn<5cgocatQ^H*|9KCB;0& zRaK4tR63)6o170h!UoSW52c<<&Q6Xdw>C6QKC9cO+A2FD*(KR1o1nU*nWF8a-LJl{ z5-R)1T1q^^>3kD^l<+ZnU(^|_glD)tU?<&}*c5$%y$crygT8s5^Df9$?ecjZ`)fj0 zY!n8C2Zbhto`$vrDc@92mg}8kq;sWbN8Z9tRx0Bi?{l;a}??=AYne?=AA42Pe9M*jR9TAI!+5i}5p&((v98 z8ES?d#~hdoJBqO)1raX(oSc);Ld}_N*<09mnSV0QQS-^G)EX#>n<2a=o-Rohedn*? zoMrZ5&SQ>axmd@Upavj_H^WeOmYKH}Ef=;y^F%C>OE8=_gxi|4jZ=Y46}|!Y<<|0c zvR}l70w=PF>*RFjj^I{uX0XMqPb`ex3ArkCNjfRoE90^!l9rO=lF`x(DMS23;6(^- z4nHc=D@^Jmnp?`&(gDK#+yd5ORweravRcpv?ITJTZxdU@U!*PNvt)gxM)V%Ck2Mjp z(t64n-x&);cjBMOEzk$f0{&USe8C`oV}xL9S;t`+ybUOIfD1H;gI3a&q={IBpT^dQ z1_qA?q`qs;oz@ZN>896~n1d5gM(g4kQ~|LymJ9ph=*ezaVznJ+6f|s_C$nMgB(Ny zrj1j@8!Si_oZ?nNPbmf2g{Z|#qg%sg{kZpn??!M2-j*R}rE;y@x9ntAf+=QC;2hza zk!`%$yf88jad5wKt2i8XZ|0pudHics5W&L9;pE^!pUrd26Z5UbZjm#Yapba~gK)gC z8^05>04YS+JT>nHavo{S{l-!dAI-4spkF-*f9YhglSeWc|pFa9VKk;TDM^VsXqAw)>f$j?N>FQ7*A> zeAtU~=&qp3^a#iTJ!7t8f8yNc9^n!kFDJ_N^8A8R=q3>7^bgdX8N!fn0d zoId+IYffEH^XZxvl|=cqsx_8WPjz%QG@bpFJ(#rt?hh#-nE90bjq?+y4I6{+K)2xE z*)#bK#PekV1*Dd1TqX8?rrQj?LO^E z34Dswqh`Zx*;iOO@S;Q)@)^D@=8HYT`^3&+r$SeP4MHEnj_4&~3w4+V9z<|8vxK=H zwt+liJE)ok@%M;(%U$wmvJv7t0zS{rJC)Jqs;kmh%poH#9qOD#J`XJgB}nR z^HhARpgSr?F9`nP6(J<=S2RziRX5kQ*T2)YP~DP#M7s&p{002Uf+K z#wlVofPYC8k?#mQIfYtI-KEEX=({p;ni@=&5|1e%dxm~MW#G+TW^`(3kIc}dz)T#D{P7l>AiW(yId2HHv#V^@MuutR|KKMiPt zI|EkV0nZBe81JIcC}I@rmSBq{NA8uU%G*kpiR+8Tpp(#U=x)Jf-Ux0D41*T<5m+SREz4 zhNqcL8*Xnjrm?XhD_ftw%g|2WQ2SjyLG?)9Rk91!@$Ye)@$L#HqPs;)MK?gSd4^!B z@Vf9<0ghyID!^IxAFfC+9rdDBg4-OJu?_Eq-3lJ^|LE)J9qnG^cv}_46JXTMpC*sO=9dMuZNx~0eHN+6oi>t7SKAUr|{jrU*A&!u(ZCxAl zc(D7I)!sE9v3_+N_3ZaA5A5(eydlph-|wNu@deOFPBY$8WIOvA^bfU|m{0J?9U$`m z0UsW{6D|w34=bWB z^LREciflk8BX*9IHIs3I`bs{dRxswURLC5phVv8m0WVkhS!5CaASoB`6Zevu6(6-n z4U^IarVTQ5)cz|!Dqe+N6;=qA@(**{Fn^`H5f%8wcyDSEjEJd`3-vnvHP336Vh45^uW9(o!J8;c=%47C0y-!^S z>{+(!whYHQ=VsSWZolWE|6F)#{1-^Z9nY(WxLGmAT{0=okM|>95MS_<*c)GSM?Fi} zm}MGdes6hGx5H9unq*#Y9p=*d4dI-q0Y6FPG9Gd(#G6$)I==3ns*em3t>$m%1rQ;p z1ALlvhsSx6?Elp5u$t@#oMG2@59EIq2nE}OsYrt816T9ZvTSWlvN)wINuwR3WXeCt z?#Ps~8{#Fr?%)ocf;A5w^gDe^d|SN(y`Q}^d|dypzLWm0Sob)Q7{tXyQ*8D2BK_C>AQ z)YNj)y3w(~^{=N(ux;GS(xOLXPUY{)X$qw>8AQ%r>C<&>mE-vy(ip((6{gm;sWt1W z2UMOY>0B5u98zYk`D)$jzUbG52gbfp9oYrw2;~;-5}i}COEFR0K)6CMShyN}iB1-- zolCv7N13JM3qWt~hFM)XXZ17-UTJUZ7ujnsCoIVC} z!EGTUs{^-yH$kwO&*Lu=G!$P{gtQxzdmEHVl)8&NOT1m!STLI3gV&Io%G$*kK^*}V z4{|8rOAno7W^&dd3wTG7VaR=i;BiGpnNCxkd?IyT$}RnERjzD{I7`G5?-E@UR3n+} zL5%n0U_wfEr2kBCAUoWKRl@85FM@u8%h-nm{iUast28|APwJ0~6S9et&*)oWA5;eJ z5Jf_TU=Om5T?KDouxKkWJiag5I=m|QD%d#O2y2C@F&j21_MIHalnHiAA1HDae@IIC za?T5Q3G@zTf}6=pDkCNfSey}Se%)Z}NZUaBHe2($#g@+2kB-xxzx|?6{qSY15P!!g zLw1Taa*o^~el1`lS?o=$a^@(gma;@yfltoPb^T1WrfGGk?U`+yW4mjEdy98uz!)@P zgNdc^cm8eJ0L^nLK%LE^3A`=U1jJLeFySJ!|SbwYzGvjrry&mZp}tS>5`Lc~*@*Y`2>O3Kod zDDq`Hq;DmKqG$YxtT2%tlDaqB@Vc;dw{4>BqwTysY%j1EI_kS0`_4pWLAQlJD{iW5 zR1@VT61J>Fxm%5%-_Jk!Eyu^IS7 zoF<+_^Z7FrgOVy!E*nm39rA`0|QF7Ku{x#8E$yRZxU=Zgp zv?SpncMx)tL%fSV54H1e@pktaf(h&a9wO%gCZZif%=#NC7Jd_55dDnyMC(KeSxl3f zJlD`Jxs$e~LN4im-WAmH7xQj%4#Q)p@v(QgeSJbe=E8Q#pT~tpb6?Q;M;a@2zJ~8$^Rvuph&I(CD)5?I(L6hNY ztXar$VHc@Wxn6ruzbMJ0lV~O?zk_@G4CxAqNtA|e;T5xQK!1~e;S*z*BHOVoVQ=u? zz{Q|DQV=&05>h~3CvPQC&N9(^a9n}YoPt6_c4%o-J$9q5dW8nk%zjPV93T>h6tkWc&*CkY|zC9pAeMN&Ucl2ciXh z)FEA`j_IkCi5YJ)+h=?;%+i!fw7haC7H<&F@HDp8uRUF{tdvpGzVt!)j;d{@9*!5j zBiIcbCZ&mUtO8+y@>p^_-I(z{RhZmJV~|gmTtjCddl*Bam7WE4y=w9+MwOqfI8)W6 zdSK09lfx=Vbrk!6Irk$IGLtZP^h#-Gr+tdYDy=rKv2+@Rj6@1D9aGcS92R$1y}jaT%7 zH99^ju*kW{60G`IGP_{vx8g6;zvUPGTA5@1$+;(Z3QwkiD;?})f$=H!s4gW_Y4-FD zsiTr2YJuXK^b-&loD&rbj&rv%UjzNj2MFby)^N zV;jwCmfk|td~xH#dY95tlD4bA%R5Rw33_lAFqB05=tOKVHX*tX=fu|%CumS>8+fCw zr0Xa?L&%)XWeeAdFtiWpNIV$-9?aDV(01>B}!4kw2v6GR2SpkawYB~7xV(&>HE(Ub+c zVX98@15%lEnE0aLU(P(}2r)F;5@h_di8kaCYBv3yHZh9WD+C`z?Zr{_FX2{nfb@WR zqG3~pG&?^ln668irEjijqUU zo~b=$8R69XLc#5kcK8oub7(eqJsOlUl~+~2DRxSI;-#pC_n5tl;lx)3^IYTW{;8c_ zy`!p6^|_icwew6O+d=o5;J7G>cOj#UAkswYRHr59r))?WmF(9ZP!-9?NXLtEc~&R| zZx&FyTG@`&y{}tj?P+^u|Lz#>8sNjR@zhaxJ^L895kG|Xkl)dENg17ypXJE-mNHuZ zRJlVugExRllN};z-&Ffq6J6b~dPPmK@qneucGo$rdedo zcHa!^C_8f>vRCj8?J9XJ-=pbcNTk~`FJ$DTG}cU%+(&LfU5TdH1m7L|5#y1{&t=O? zvno6_|Cs&uw%$3N~Au64FL zbD&yO+U?uy_uu~R{_d}@@zOk#&#~0k61#{WBWE%uv)2e@vO$_XhE-|J)3&F*PBkUJ z)JZjulwIT@F;CbR=?3B}|FZt!Z0F^GOf?~yp*W%K4Q`;r(>J7FOYfSIm7Si0HuJPN z)*`8CMgv*;TYX>kFvV)=2=s4mTcE|bkDUt%!y_VRV&CJvNDI-IY?e?nuW}9}Z@BB& zW@cCB4=f$>gP>Bt6tKCTgdui3Q0m^|psdX;`)W^B;-yWB2N#tW_bk6u-ORkf%CRqY ztaaDse<(41JgN%c#Ys*@f>dU)T z&a7QxUGIwe(!$50d*XkPKhUEYotRnNTLP`5v;3)?mfjbIcvIOiC_xV;ilc+D2EmWs z6YhtuVeW+YYA}H9!Kc!*nP)g<+&ttNZ4o`ik z?IlYGQTP~B0JWm0#;;@R12?@=9~xR5%_DtKBNmUnl-pO(RFbb~r5>kNDvk1hVwK9P zD^8VUtV|uOyC7YQG=mnBm+?o@dRXVcUiWExL)&pXjwqdTX3(JK>of>KIkU$0SB`ABy!V4u~lUG)zq?Xua=Q-5TC*a4O@X_8NKxBBFJ{ zX?~rjuU%<6Q?a=uSlpyM-#FFTH83@LhnxxJa_$R?Bp!uZeN5Ll`E-geZCJ+Ubf@96 zrln*lXBf2}>*=ku#Y~#&g=K%1v@D622rCB|aqD#N8|)SFg7KUc;NtxKq6zXO?M8z% zy)gYlYSW}2mH(jYIY$z&Vxd4Y*CI=#8m&;3T`I4uoK-W~vc~?Wn;(MWFdXLf5`U8# zrM+e6lsmOP!yj3j>Stt6O=+r>@PQUT_9WQP+r!b+%&EFta;UIgQDJF6AU@-IehTVi zA$l&?fi{)4mGzXB$g?yD46m{-HGJ8yP1Zu)BjNHyFud9$wkMl^uR==lzLkDl^g-}h zSAEH>Lw)*NZXiMnjNhduV=3RSA&lYGaFUscp9?n|B=2l zIi?w=*dZ?A8#()7ih{`p@fNXNk$I8y=)%}D{3OWW7RN8gC&bg@P2xS{GvhuyH5SIS zp{UR9Iqcrydgf?l-)d`XU1>=&w>DXf7mV|an~V*OPisHdjx;Vd-8SE_EUD{nZDQMP zW7^I3b&fE|-feL1b3S!ux&Co2anE)C<+*9qw~vB#+O(!S5uvDp)5F3Hu4}0Y$-dVU}fETJWbpD+~)GKpB@I&J~?RN#Qc#B;gOjkYKj}5^Uu=cr$r} zc}YA92_Qcs=eavLW7!K?*O^X`$Hw4WZ~-&`ehb}YT!(hT6F`8EXf+fOTv5(mAk-^b>QAhM#baeDt zba8AeehPQRCgV47GPW?rk5xx&q8p>~=-bG`NY6-qWOXzpwm0@I_BrN?4a1k>Wq4lv zOnhYAjK9SRym9>J_yB@KhKK~Qm^2gLiQ{ArIh^1UsYC|RpSVqgh-qYqoJoD4+R!KH zC?Gb51EQ@xaH*=Luh5zFYicXCo4Q1qsI_z_P@%CAsLJ^t2a*ExIzm9Sf%@Tq9i0Sp z>Qg~m)q}1>hu}%@CE)JY5L92O0&Jp&u^W&`s{my(ACMDcpn1?}XeN{Zlv-2p^%6J& z(tvDh1?_+`;RmpqnZ)EVi{ahy7I+2R2u=nX_2+YP_lPn-h`U~oqJOghyH=S zfQ;UJcp#I_8o}zs`i1q9)rg(X{>)m%n#yuA^H?a$16RQaGli)HI(HRwD;xnTg;mTf z_#Cte)Qofh&x9KAXH%l-|7y~{0Y0d^f%>Ez=;ki~vZoYqD^0=sZ3ra;9;*W6cOL>KV>}>h zuO%)4jYSS1h*=<#*8(s#4muU^ueSgZaU75X9{@A)pU+Qgz_GZ%`^o%YUABFI>52jJ z;})PYjDXO24OIA<)GP8i)fm*{d_fxkCBX+o&}6{d)Pm^P4dBT5pYzav?$94V&*lNr z!U*bmt^v*jO=*}uPEDs&)Kzjd86f)uzXBU2rDxFx0lQHH=)tjoC>aZA%o;!l{tcM> z?%syWq&!pU-SG8Ls3(MGx0lkQg;5>kW65oAk>4W4}hP$53>{EfgL zU?-p_ivb-L1O&=W5aX-{?kYIF7Vxm60I%kxdxKuuPB#U8Xs7o8{<1S5dU%Xvhy=Xl z4}e_x2uM*j=)WUSBj_X`XLo}CdIK=2R{-UA9?ZbwfP!uf=uJK7kzIf#sRRBt7l6Z@ z7wQL}h6~|)U`Abrhk_aND^v-H-}k^b1OfGvPJqAO0mu_KXv_atB@#GxJY~3`P4F17 zUY>+ML33aslfyg*cZV^kH?#>5aW4SP6a-}TJ1{N}1FGjV;8f0n-g`!`qMOryfcE$b zd|PW7KLDQ40X(7x1A5N@bz-yyJWz7t0$5{q)BEW2pt|gQ;0W-L76a$4h5sA#A+YZF z>D|Ch;TOPo{zt|x0j%3LFshydQi%lZe2J_`X3qd z8yKa30(#2B=nfg6RPc_QfI5gj0oQmNV5Qi=ZS4zvj$R4;>f3-0FtFGYyEh7iKaXH|d{;ME95AeWz;1&lwzUW@S7v?Xj9w6_I z0QzMz)fS8$9q|5$fVHC&Gz8uU_Ly^!1L_Yi0=v&GpoVe)pPfqDKwkjASwgA7_?bhi z=?ZE-Z33+IX2w$J3_OwffSJqm!`r}U)4+M4hHn$FCa!`9L9xUsdKEQ`+D09rLX?pH zNR0twegV~q-jM)aI`9_eJ3#qFnai1GW;%Nedp&D3a}8KwA-FSm2M}BWW=abxg($~a z_^ViNyaewJcCR$z5HXcpKpANxqdUBiIiJ;;^?{Ybz6;jPq0C;;d(abQpc36SXcqKG z!bSzCdw{^{i5u{(xE((d&nN0g80;5sfq%T4;e}>{71qJ3U>#+u;00hW*Z{qQQkb1t Xk3epI05l#rO5CNh=*EEO-kkV9+U_EL literal 0 HcmV?d00001 diff --git a/3rdparty/chromaprint/tests/data/test_mono_44100.raw b/3rdparty/chromaprint/tests/data/test_mono_44100.raw new file mode 100644 index 0000000000000000000000000000000000000000..6f39e7d878e7225b95b3dffdbe5b8d9a6c6ed1fe GIT binary patch literal 176400 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

A9tRnLpANPitk%F{*yi6ctX5?zj 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 BTy_8e literal 0 HcmV?d00001 diff --git a/3rdparty/chromaprint/tests/data/test_mono_8000.raw b/3rdparty/chromaprint/tests/data/test_mono_8000.raw new file mode 100644 index 0000000000000000000000000000000000000000..14d35c7c17d95bb8d25604daac35427df8ccd17e GIT binary patch literal 31982 zcmeFZ^;;at7xrB}Gcds5E`hlF#@%(}?(QDq?k*c8?(W&xZrpX_E)YS3%OC^HbUmNu zd%f5DA3Q%j%f$xi?y5THKKHrLscMAyfB*g8vw%`Cl$8G)QSzSZDYf4j3VtW0!j+PrD#D(hY5!?=s0B~Z7ksY>?LHeH|KA7-_i7*i|9^U}5j-JY z4itLjo){>ah$^D3_(Q1DSCkc1MLp4+pXtRXd0Sp#271PAF5XGAtRPPDlU6cUohP5k z{c^oLBB#kda-lpZU&?4cyhLqLpR3D=3XJoXdt&8zIY5>ZGsIo_My`}6WF;|1rpTMZ zStQHmVw(6@JQhzyjCdlh@!dpmL0Dvh+$PS*mufLNM9!6)&EJ=GF+Ar-(|dP!EYakSk`0Y!-3y+}B045Wylu)D%TTWv;y< zuSp-#Q*4ygWSlG}u813=uE-VB#b)UzQW(96e4vJ@Yt^OdQ`JE(lUee&yv$tl9Xm3*%$jQk)z~OIYf-Y8*4-fQHfd31Ho$lD zvb#)IJ>_<=Qam2?qTWe|RNC3Er9K2{PXJQOG82Z$8nKK=`p zi-_46`3Es#R1!s`cqe{>wRJKNoHi3*LBj;GR7R@TuwM%PJHe`E$pysvTxNfqNL;~; z+RGx$-cvX+&nP0ID04W+wTpRvuo%yL2Z=B-lxq&*!%K3oyotx(;+0owjCu>-2XVKV znE5UB!W*ykX1zURQ!qFIw8X&_ml&&}j8lK9$IG`r8 ztbn(Av5L=PuQ)HyFxw2-6dY{izO6*qAy)H=_3vSxhvB(qTwNcwdI4UuiL82{GKQZ# zlwE{XJ*|$Bfzqnl%i64F88a#?vSnM*6uv1Y_Q@Zr7kro}-B^1^v5Hv)iH5LjS?1_2 z;;@OQh?HsI=9w&wJ>SRx(O&!}I;YBPb*A(rDxP4wT~dL!7RzQ>_zQk50w)BC82OWk zeob60ko9FfIg==LXZ#(q7F-o8cZ%h3@pU+4Hu(7fN-{(ZaIzEBr^=G@hO8+ZuCQv`M?4(s>A27iK|t>lI8u*PihMR+Pn zjBrLY#(q1n>>Os)M@F))20T$H>EajPRS>@1c@d917CU5Bm};NwFPre$ji}lVVW)Qx?i4><-pVyJmto7 z*NW3bP!!xWP0Sa5*eU=Im4%DVV7x3>G{<)3;8YFoI-awY=M5*KJh@}LcrN0^Vtm$L z+>{?=OL<#ej5RM2d9B1h;;T3>?ubdS;Z#;?2kX`4dGq*i0p7c(`rx-B1xzrE4CX77)IxAe2{7LY)_Bc|d%=>~u-YMcnymRBK22lg`$3U` zwg1W84aEVTDMTBQgAXpr5m;vl5&Bln1*M)?W*675gry2$-zXv~61JQvTN7ccv2u<) z%l&tV{`Gh%fv{=y{TMO-V(R3g+;_;fpKqI>F4$GU1=6Sld&i%K>0$E-}`OczrJn%44yRl|-RW zmNKt#Re%YAO z)|0J*nCmm{{|8GRMJJU6D+#d0OxC#&i*DijZ*q@lsf>sH1LSx0UpW-4hQVl!u-{8@ z85V4gjtKzK`Jl#$I5>#i9--5Ywa=}q@-XGk55B~azva7^uP6%(Ms^Y4A#wRC;%cn%tIJFm=ZUL*6 z^1KLEOyIPp_?LXKn%Q=Q$Jc|CF>;C=$V@tkO+@i$F&FNOA%nh!ONx_IS`!6Bu*zc1 zD`4~+xXhC8;gKWE`Y_MXbW~fo@fc_^i3hA^E#A2=jc8LlqR*fF?ZP2lS z#K01;a1)(*8s^lYy1L=(p?oCb>r41Chy3S>CK^mWeJ;zemMP*o*htC#fd6 zQG|;uGW=9Hsu?rXv6={CH-M*DVbdDi(;BN9;r`~#u_}4Tk%^O zYN3T#gSYP!_lxBZJl!9KdJomH8k-#fyNzX0;@~Xty+Gs%cVaIB1WzP~Ea9ikS$lI( z5yBH6!9Gjj)RAz_GO|=h)@X&(FR)S_*H;zAn87*JOEUBK!ai4IPqfw-@KKRS*pJ=H z;k6%f7*?GxSHW-d@!1ZZSd$1F!}>~~Sq@^!TlnRFD?W;ns9g|C-?<}<&q3htHF|3# z6;W|91TI)dtSo1?mqEfyFd9z&ttLCc0v^PS6&`8``m2gU*kTsU`BGLv0bPdOkIJ!V zivaw#ggiVD#w!9|>oQL}P!Yf#q3~@J(Lxz0y2!C8!JeqfzGQ^L_+lCnzm;phgIqiD znb>&AXt|)y3@)!yt=NkMQ9_vl4}HPrjo|8G@Oe|X<{}onT#zkak==T9@WKYF ztaWlY9JLE9#miyhu(YT*d8PuRoPq`SvA!wjvtwA$A|HvvA-z%%yuNBcgMz8;ejC5-T+$;BYsZ72M=WnsU!c+hG&X` zrgCJ~Tj;MsVh|ecv-%y?=Zb${q8J_!3#VCSG;=<}+>+tau`otas+9n&IaPdwX-|OZ zs;s|(+zG2D6G=B@B7Az7F~*beuaR8`f!_U~J%RkRfH4KJa7Zjs3MsLuiwt;P&+~>0 zFSsQ|cH?)K#6kQTK~8uf`|@=O=6XX!W643>@fL0wPh1>D6Zb)_3<7nluv{42{uExg z$U6T6cSB&&jwrIKa8jVSPIPJY%y2TU7A-A_<~Fc$1Uc%G^hWP2;2C{b`!TQ-OpQ<$ z6wCpmIjp`Wd{7AMbtAj30_ok*ENNiqBbK-4t`0IrZ6jY%V+@7^;$gAkaCQk;E=#r} z=Psc(T#mxsjx}1MnriUe!rT`m>dQK?MHal}h3eb}&rTq#rpew!P*i&yW zE|-IO%3k#MAS(Bc)L#DR(Jn;CRBDi8B8My<&s{1J@(eVTC+}P$axJXAH|y;#Yrx?S z*m4NiKPh_4RP`J_>IW+gW8}i{?a<G9s)0OOnkT1Xm07YES*!}V@V2Z*^bZkkk?#)2WDdMquUY&x$Vi#qzB5UCY*N#J#z=;Rf{$6CIhy^ ziXEBBA{ed%YYfI-5%PsvTlS|idCpji@Uw=U@60ZoEZc#+x)B!W%JT)>5`gdDvI;-) zU~MIwXY7Q1yotuMBEO)zj>a}~8EFD}X(lUsisd)L4xw<@XPKuSkSE12dKwD6=`B*# zo9ZSM&kO3SV3=z@l~)w1U?8h}E{|Z%Ks>gFIZY(`2Ef0cQ9sQY*O|O@4xKVv{z+6M z$)VKfFR}3e(AP=+ffm`PMyuCh9DlfVKPu%I_547twZbT)Q6-L`Y&;qGGzbnM)_%$Q z!a*6pSYQRVde6$nQS++AQ5~3X82@iokTDlyl`!mioH;iY%fRzxs=8RPItN@m!}A}( zug26*z+)nubR9iqN3?vRf}H}t6(X|MxHN zQ6TwX5}MeVD9Vtv$x}!0Q!Q%KEhx(?Fk@BXK}Atq1wGBMt1~l@%peob=a2(t;6)Rf zq73zK80t{#Kvt&OilG{<#Q%HKd)!a9abkq4jBtcn@)*jZaDlJt6Ez*syQ9cVong90 zbiSU!T8&XJFUX09P@>)W?NGSU23KjkVGm=?g75aBe3E&(3t9FF9xF;GuZJ*`i+X^t zYUsYs{NyXF90_MPA*M!v^QO$DEyx_t><{3R!LYKbF2mXt`PskdrxozwexCLQ%=``W z?!sp0@yKZ+U&p=ug%)#F$dQ+@@K>Il4l1l5a|JP|b+FQjvqk92Pa>I>&V`xI;ek=~ zJnmqlYH&#imf6Gj!(iz{#OQjSeh*Bz^Hd`?*Lr)$;pjHx*%GkLC75Fu-tbnokTd!z z@5uN!u=ZZx+fLqTkblE8hXmT zwNSUcsB@Qrx+Y=;S**K^P&3u7sJr!aGp}HOJ#%p3{=4+F^QpX-VBtl?N(rL19o?Eg zP^6dWU3KNBcd2Z;ieY4v`mAsXd8Gk)xDKn_fnE#Y`cnen;OR|RC6ai$4)(OJZD|lu zABNWYFO9%<2|AJKRB-db@DXCB3%{F3=W#gKdW+pydJviE2bi|QW?#wo4?w{?csmRG zM`0DM0+OKn9X$3N_S(X%_AsluqMkCHv2KF(O|W}&qCOGZn_<1O)HKg!QIu6Wqr62e z%!NsP;F-s8OmT4SLcF_yPh@MyFPJd0kZX;fr%384CMP{-BjXMxs;Hu={p?}D&?YJgR?j|d@Wt>K= z;~oesBp<5(sg;PnNFphNj>uZ-(`r0%2_vVmE@#jf0%LRnokPKORV-2(d{ieg2EZ6& zSWR8l7frnAB%$3e)%TaBMut5-Y-4!CaJ3bl+A1=mT5;KMVD!bdq^swdAV4+HH~qnPzt#}} zKh`^jD%(s%Xn3&Eu~Ub&+;r!=)&@TI7^j#8?M1(^ow7lk7c@ zd^8)?c8Ra|l7+UTLJFfXo}k{pgGYP1a(zJbGSGIJ&xL5-Ss=3;cJUDXS?vnqb0~bL z^)ox+&*9|dFzSUzc&r*WFN;#~AfN7o73@&gZQ;I|XrYO8!rs80xva>HFG9GoI=|O} zj8<5$7I`<4JG_{W3rsr(E^Dtezdtp;W%qfjmr;h$jn z>BL|)W;O(W|0G66p>Qu?zdP`94Q4SLKWg3jjp&+{jMW`&F%En!;v)&YR|o8lz#31< z2>q!~Zxv{jTPURfeBT=V@dx_8Ft%t4Ito!cy}>IPXtuSejf#Rif{z0D=ncE?#gd)D zRX^@}L?${(z3WeGZGa!{!>1SUL}zAchM#AEvm@-vjR5m?v35G>jO6NKptCe~{R6&@ z$1jhtoGZ3#${Lr0>yOMklFU&W)PF8eksHXDor#XqV!JXxsSbDgFwerGJhlBQD$?d~ zO?ZJ;%4B^r!OIWqa}36cWOvJv+H^C#IT0;Cf}TlrI`H}GYHYfJeCvx=3dOre(7>Ci zD?Y;n@2Ep05vPc;@A`#TEQ z9-PmEvz<`K9fB^Ps zSznMSrnFa@Ve=PcvMgfsC(rq;u2JXk+huf=+7UkwLCi8n?1fjn(b8L}!3J~vIQ+E( zA1(t$F=$p-G(a0LVWG~eN(42+wrv=3Cs$~l`kk!wBYCntp38vav^ge&+4>+k5ARh5 z0SVZAKC!zMG!BLVdeC=DphMIQw2Z)eJE^*=u=00k#J@y}D9fJ58|>1L?D)O_Bbo96 zI~F6T@_MpM(FrWnB>$IUwj;@7Myh8`iG6?_HW9zq$ehivsRi|37#szVxhrE+tyBLW zEZq&3IxSQb{4SVW#UeGR%MYq$@%KLV**q0RsYpisicYtZ4@&T?iF7VT!GR~#_o_1$ zgN5$IIe6wTM)0Ed5>H;cLpNt2R@h5_<{z%;4%W-y;lYgJjtbZI>P}OWD5#4ecySc< zKqD0NK=r6P5w2^4B6>g;I|J(OqM{EIM|EM-9-!I*eD8r9D!@4Vsn@r|EDvFpk}&v3 znACzF3NzCPa^_c5<8896R@*iM|7}@)U!{ohhB%{#K>YPURg?#9PGC$WC*&5W!4#rJ z>vySiH(uk5YV1R{V*IVt^I>>x4tie?=IX+%=XmaPMtBP56X@<=BX?+3atbjTMUP;L zny22OCh}8~#VTd3VunLTgE3z!a8KqPN32h$g7c?NZ=vM}IhCJOVx&7aA!A0JC0pL$q~os z{^Zano<}YTCjUMrpXRfUPjWPtRM99+;o;&+Ph~7hvbS)D<@-?4Z=o7kf%ZwDhdmKr zq>wvT-~k;9V>!_rh+R5x{Qy?F1tm6spH(EfJ7AAtpmHd>{xEg&Nut@C3b>}cuJ%`F zQbqN`0+qxM{C5lFO{7*H&&uY(d}HzF2^8CQ_A!jC%9FV4ME7PPaX3!4W{*tDddf|n z=U;$1pMvq-K-#}#c=oo`fka#rYeNyFyC&V0jl_VzSYUXsj6+;tpQ7*ZufnulJ5xH;{nK2_>MFc-x-Zo+Ag$->*2Lu9h| zTS7UnWN=*@VWdA{CuUO-ynz)x$kQ#z?%m1reK|$c3AE3}lZVN}|DyLY!OIZF^Cy;C zQ|HbhA53S}4S2e?zv~WTt>Gg^j)MJnv5HC9?Fei%0{*qJiyr~U+(SQ(;9gB>SA=o$ z)#jjcABJ&=+ zd=L)N>Ml<-YZKI0Pv+1}DXpADqZVVnxiIHzp7A$X_9$604YsR+ePYFZ`gSW=#Xr;u zZDE`=tT7eKZ-E2bqbHrDfq1?O3pHS!?}+xdtkPFZ<8(lO*3p=ezo8tiGN*b}V=ZB$ zpV+=U<2HrI22dvrrGBW(`n%z$88Fjw5YrF#*5=iY>Y_Uy>P5Bif)&|Qt@yLjYSdDi zy|s*gh@FZ~oMTB=XJMy0^f=Ga+xtLuu^KL}L|@yc)&fJzsr#-?xss&~B3#P6F<6eZ@qp(aDu?I~%49u*@j_b&-kC@wc z^5btx1*l7k;UztW>%x z%amx)F^t@qh7z!-x!ClLJcZACido7GMX%5;m-E!Y>RedEM6TSAg4ikRg1-}V9x4*s zvsmFMDwpwme+iF9V1)qKek?0}LH6;3DZKI56wvmPneReN?!iwFP&gYEPk6bHqQVV6 z)WMHf*BJEH4LtLbD!(_?aVsjRQeu)^iy|9^s<5Y4|BQWy6R(rVIbHdvN!>jRi#y}x z7F<<@k<2{j0k!47e6<}dS%_Q|0ulo8UqzI03O$!Rb^r^bsa=Vmi_EPMYAT#L_W%v8 z=sl;Yg6F+u*Es<#w~P8wC_l+i7WV!s;G@oraYW{*S5Ok#2?LGKdV`h8@JJ_6_!sC< z!Rt3H6#(w4;=OD5WIEAu9cAx9KAVZ!xq)`NO4NM;%{{PiU1r#rRrpgk{EyXAK*emH z(UDqjnOH^iXghm9P$+e=QEyH>T_BfzX3Xa30XI7C)mgz!W_N~+-a}TV7c~d9rJ(Y) zb9&`KRx`SMXF07>MDbGg5D@`*ARQZa!-^l_hZZQHrF51J#NZgXL+dTxqJp^3Sfl8X z9)5^DykFoej~>hvv%*_pRr9p znW$!>kIrKmd)D}vc=(8=yHROuq|&yss~w@1f&=f-jcGvq9^BI^X2M%%}Ap(+i-F4y^gLuU9jMhhv_A+iPUx69p=B zGf`a=Rrwfp&f-ab5?k9v73Bs0)~4I%&b+i8h6KDi7)7)c_HDsWU(ofKNNjFm{9B;M zo&D@2PHcFSiBFMDGEi7Y$hw!wpA*O*$N6_F$WOrLPDB?wHQ09qk?|QXR;3%#3ZLyp z)t4pv4P*>6b8iQ`7p4DO9(z6G`Qt&{Fm@aRVHJfHrBbzQlkeSg&D6D+V1KLx?prRauwW2ZvIs6bDovs17E^*n+Y z?gZ=opciox6r|wUII6myDA;f@Ux{HgTd44kfOQ)`ZzOa?igpr5+he(p3W$M=&apPF z%dF{TfA+^3;&&f#Z=oIDsnb^3}ZPlX8|^YIED_Lw~8Ohxw(ecWi~J)GUAAgo!8 zmAO)LwkGE{Wo6y)#YQYw2SxIhNRI?>cj3dk)UA0$nU+6_W37t#W|{nlir^UdDnb|9 z%9>-XaVUnJVH<~Qk6My_>HdlG}h62s-fEcI;Lgtc{_o5#UqG4BZ{a~W*3>Lgg zwUWrQ$Dp9>Im!D&MzOYubZ^GM-6zolJIPTgJZ&C4(;wZ{ow_)nAiBQcP3_EPZ#;V) zE}0C@KhpzV2`k#@Jk+N5@QSFeL&yFbY>~-{p_5=G6P&b$@v4H@uPBdCD4$58=psF# zYbdk`5IPy;8p&f7sm$v$+e7%nCbxp9#sxhQH&nTH3a%#^{15sy`D$gNEtr+vCvF-j zAMuZ%&Ye_{d5`n-T%K14Zc(J^n0?Yj_>(ahS41{uunJHwf^V4%m$u{X>$ z2M=rg3w!LpfUMexi2MNhYVp+oe$tSfzXLDSglmQo1y@0GYY@~|K2^27Bp;aI8d)!j z*m8h>?!f=OvCsh-re2_ekA;gz!oO{)1e!2oZx|zwjGsWVyT+w3eI|? zZ@p1^SA?5Vl2a8cSY-m7ty!`=^Bg4hQgdj!D;}Jr@{>t$bPZIkiB7Plbc^%Eo!oB| z3MT-b!x>-Tk1)=QpTVDQFk~P<>xAb9^K~h-g)7YQiFIkGw?9$Sjl+Z5>HA@*mGU4% zUvRc$3n#bs@%;(VQjUMC!gLd{M>LhkNLXhGJ%)#H+;n;uEqQ`UE~tq0nioWfq#LoE z)zl!7xjGSJ#1e1NQ`)}M zA9%VN{n!W)U71?D1^0EuM}4?zFls#y{g+41?S_u}hP7W|nII51gs2c8=oQ@43rlrl z-aYWiClI?2G}u$&bYT{4KviQhy%YKTH`%5r7QI6L3j__3%y}ltFciOdk=Z-KTjlYa z2^6NVf8|V!6+(kvV_t69xjgrcMDKfuDWJX@(J&TFc4B7dQ6{Irfu=Oq(rJ8;kDI{2 z`{*=P=05Gj(FE-Aga~{`-nNjVT4Q|!djQF*BlaJU$286KAG-WBIiMaMj%CL0LEZr} z;9VlqA3X)S$kL@)n+wIS$FTM(#tR))H6hwP@ytM}w*g^gafl zwOxQW6ZrVWhY$R56XfqhOLrk(ccS~y7RybnM-aFXrL1)s269^9K2fd0;0=k4Vc_mHd=^RvVGJCsox!a_?_m`j zybQnJKs_G;LzA$d4?bH;7kWE&%1$EA36Bf~rPHZL7lGiWAn!ePdqI3Sf|e~r-%3W9 z&b&)<_b}>St6U>S!x7Pp*%oCN$v%8FI;m@!|2q`%e(YC^a~9fe)jRaXKrnfn^=D(_ z2u{RIz^>bfmp`zg8B1tq?JpI0sxenzK)Y#Y@K<2-Hdy^0Hq*MvyUEZl@WUGHv94fO zFNut8gvsYJw}bqq0m!-!JERip+DWKLG+1eJPY>4B8Pv8!9T-?^dG?l?@U;gcoupHA zlwQeobeVQ;tRHi_!%pIG_;@_{)ZR?$LMB)bf;-Vk>dsTn;_p59`!aL4QX_0d0cv&n z5Te(Kn2Cn}1Hj01Vny?Dd1{Fd>L?hY5s?tUmHFtM=gc9$U|oIDtZtmt=udT*no4P`ll+XkR)XL%{SI^pdvA@BpMm@SO|TY0vi+iOvk- z?*=Pagcn!if!_ruP?JGuINo>$ho#a(Da|RK7nsL?hR(jfYOSrtP?7= zGRmnCYD7<^RhQ2)Fik!)%EepGM7I}XtYE~2U>D6yY>p#4kE3=f%9Ga6!$L#@5R@&=Adfs40e{l20p`X`>6b06Mm$ar({tahH-i7M+N*zYMrs1k{54tiYZs*lD8)#M(uei-~=kFL3d^*3_&zcAuYvRYLlCXD=X5iYt$74sR)L^Gcr z_+%uW`Hx&!4pwb~bv4zgbwsLRyXV}$gsYmtF79B_0Q$r5?O}A)ICkS6ki8;U`E<}8 zh5x3JLE7Q5RdCcMxYh%%E3SAb23TUUVy}z?AItguE-IzT^pnnUS27sV^5+-Oq-E7J zJZnEVtVxtyAkyApgVuCjKEQp)(Y4>G2Hp~#xn$*f)V`JYU0LQDOZNMR{5y!aI6(Yf z0{;i7ZfjucO>o9SYuh%yoDU7^-_aj z4i}WQCZH0jKsIv*o9HE5&TZuSJ&Qbn#0%c zS#v4kry7yv%CnuY5**0-3Ny}kp1*|n4Mee|kjZ~z&7#z5+FL1|m`{7Gu$Z$s)i@8( zn(o6B>g3Jk35I_T3dYez{gVh+xN86_I0)Vc!rm4zo55U)5iQy~LYIj$7xG7c z{22{jYwxwx0s+3*ur$#%4CSl6>9QUKd*c7*tavG&-^t0B`SOga?fPutIfKCKI##CD z11`kkXZe*L*j9Ef3oHA<$ye0CFveZY`uAcb7joeuyj=%NR)A&AWK{=NUKp#`!8ZHR zcLA)o5|)ibrH%l%oAHzOzF|?~y%ir-nP(o^Dv1oRfPJglsI;eC{WlgViT;?te)3qZ zZHFEUK}qyrMQ*J1Cg_i%&-)#{bBr@1r(or5ETWxS)A7`b%q9*?X2GaMLCZ*AlJ!pBliw!|IGKNm2 zCrCYrH`!}tjvwS+t*QW-Pr;NU$SDUpHLPUP6|BNLWubIdPLTay!11*}SvB%k3h|-6 zvv~zf+=c;55UYKtN_sLzZ4l9%jNKB9pXX=SVWZY`le7x540tQURhsxeq|BHm3r zHy_rsBhuCs>=O*+_cuXI65am=^jWmN(i9N2h0(Im4|*_UpsV+o&RP`JmXVI7fxo%X z9-eTMuE(;PkUeQ~Pif3e;!n1Z*l zQ9F;w`agL_IMv2#_;)wRo`y%ul5JwBL^Bw<1$)JF;2bXyzKgxDRn#2Xu7yGeNApTQ z)Zs&-cO|PY%35m@kuJn{KiF_M86gMuXv64ZiIE&~X#`KL3M(7I9dC}JlK+Nh|3bYk zW@a~Ft{m1M%$?d^LP@-;6c=L6@nrdujPFe@`9Rz>V#KP%w-abCfi(xf9{zmZLi6<@&$#h~ZelLc zm&`7@JB&03Ol-mb&tU@%v%z@gC$X}Uy^%HS`cDPJ+FOAN`1S)0+KK7zFkDG6py|fT z_@oSx8jOu^ku$W@F>i@e-o|3(e-H^V@Y5}D6^DiY_r7djaA^Q*PSln;FxNxW=MgHN zuh_UHD}Rql8pNr&9oTCls;~!hZU-LT!2>rzd2zZZW8nu*K;x5#WSRlQX%CpLJn{24 zD=~xazSwOJHQfbJSq*GfV=iAf5u}}U{y_$Rjh9ZrWPQnOTj8)+R^1Tm700UYiL4kf zP@B%=H#PIfZE$4O|Ym5+rDP>Fe(on=fDEsL9KG}1I;=3=`tMC5B0N%_}|R^ zPB2j!d|!mIv^PFyl4Z2rnK@*Wx5U$I#_p({^&%_Q0&`P|-D7-gM-lj=Pgj!X>VPnR zdJ})*_jc&Jc&z*fadng5E@YPTQE*M+*Ilf90$6k5oq$BHeTDtXVA0~rHZqtC(UZ?; zok8X#lw}_<`3-E(qE5Pn4N8&W?t!siXt7ZC>L#%&D{M6f_WqZ*fX}G@bkVwlv+Jy? z85a6Y7TN_b_CWvst*((*QGoY3jj;;fc4cH&n9hX7s!-8w2Z!~s-*0SZ1wDna#(45b zAI59~Gi)UGemv_B}*ok0g={fr&6|)|B@Q!_{}_`?Kmt&UD47Kh?|XM)jilLw%=SSGTA& z)pXlO+b>%ub(XqBz0WS?H|oQRthP1#R8d5FAD+{i&lc=q_rtTx@%|@%V<5I_qI$OC zw+VRQ9Gw3MjnIfp-xw9`qTDBgt-ubE?AN>kbtWo_0sKZo+II5%Y8d+oJ?d9-hG@k} zoB+i_Un7#YXWi*1#j__k2Vbos0=h6(J=S{=@4o{f&**J52dT^GUYFyF-F$4p20?TZ z*AtnQ;ilU}_Drswft|}zCAp$H4&bc-m|oLvV~MKrD0?5yx$NM|!#rmQvpo$io|8R( zz(O5~uo84sjlAb|h*&F+nwpGi7zRTBz`LA@hOKYIv=RLFEl3?p?{7c8DM5T{@AQoa zd1*Xj0H|ri8Zu$=heStrbhp+yKLuJJ5TA93r+a9cLcEC~)lTHvPbj@&M9X1zpBJLb zesiv;w>n2Xg$JY59MzW-Bn_GAcHSy{At%G^cZh{;*!ewi5k@S|W5@S04A+@)#xs(E zYbvpVa-eJ#80`f+9j61Z4>Ub5=yGXi;m47c+k>;G^dnwk|B~pdXRM(P-YyMezY^K3 z!%-Z9x$4n>7{h+~@`7EXGgNNVh@`5-c^i;1vOs6gU{7cuXL5A#RUh<4Ine!p_<8`d zoPm6kVpPBs?)Lt+AUkSTZ=9#t8L?K|ZHmY_% zRY?=+O@DYR8M`L9+Ce59M8~)dUPvUr&!dBOm(0yyE1|#E8TRYXxY~>g@%v}^av6$; z^Ox$MRD#Xu@=V8C&!|AO_a)Aw#4A(1KwSUrx>zvOK?9A6)>(qJ-cy2tp_J>a#aKSBm-c`T8#7oh0`C~d6Joe!9^Ps z>P)bw)jln`syY$1ioKKl@WCviBoOAmM-=j=GrrjcALQ`#lk`4(c~^5#K^?M-abr0j z(TKmd+_4%tneW)=sT$Lk=kI|R3XJ+5X0KR0&=jfLZo~)fAZ9v}o zg-6N}w@aACX?ml#IXknQh^Pr#`r*;lbUM1S*EAf@YZbvY{{I$FJR;7{vd4RZX#Rl$ znnTQGkgu zfbgBz_z|&ij=uPG(AXSKatHmIPMgC!-n-Bwk=SM#$V(C(mG8<)e6S-C3hERmN5DKMqR{1@nhMsvi7zAv*8FpDF4|b)I@lEeRuP=&KC+ zAE@crHHaGZ9=kX$XpOb3Yc+=n&2!p8ThpvSG69BpiTA5<_i$o!H5se{@mPaZ7Ul^>_}3TA zWs#pY!@>Q?jAyy}U;H$P>|rH`)ZlNfY+=3gz}r&zPkTS|DjqM+ZR5XScLovh+Bne$uEGCbIA2kFHUapD6h#?yA8$j(`j|6i7Q%^KC4@3VYb_ zmm8TP)ji-wqiq#eo zFN0X+G@|J-F|Pg9y*?mKGWYgaavC3X3$nHs-`xSvJ;)x7mF4(bQ=!YKgg){<$0IQM z0`wjvUhBX+uBf6&Mr;U|%tPt*fUUbJW@RB~Mh4Lty9bwA$lpt;TfU&E7f_2dM`vfN z?eO<4X7U-9`41mlsks=#MmIIYzY{WFi=<|nF| ztHe0xA&B*BoRgkUhUPDzDEo+}LcIIhjuRyviTiHMIv!l#fw%tF-Zqf?xnl?jtj;dL zZ01=X1=I+>y@8b%V@uA^p+U5>mv^byc5>BzGT9fD@!WjzPm1K>0#^6+oiC7$kV7{1yEHg^z}H;I#Ukwi{7NEI@l z7~Mv`h{EHSdG<7RYpN)WitjF{Bke=Wpg>KAcG|wB}Xurjk>5TX%?=cC^4h^JUevVqaN|e^1jv0p1 zn-03(s9UL(n((|xxNwsiqWYo3w_~NZa9A|<-3dPi@YN+^Y6(1IglV+5hh6de7HX4q zWXyNkP6>M@{n)KYTG#N=!TKq`Wxkpx^2gwG~XkCS$=)% zR$DFJP5G)nZTG~krQwUNz5b7M(27CZ`G6L?@5yrbCaK^eM*0vaW=C`E}dd~y~_g6W}d#T zo{nqm4%$y~I`354E+wyMT5^1)_`8XtQ<|mzmAWEhVP3X=wbNF&yRPnZ}4f_`+we_{=U(B1qIV|DO1qSOQ+05h;5j`otmyC356Y#Nnijmm^SYDCp`*hk z`;8(q>sI3HxR`jCv{5jU35yg50+Xp!N_Vn7}^0%&i=F-?25$(U+ z{_-@u_0RUvmlHo`r|HVM*n7?NZC7YxvC72*f?s<|huiwMBHWsnl^tIvBIU#J50$<( zi|qelZ`~4NtF~mJE#!mztEcU7Fk#bSRLjt-#WVmHC*ocnd(7lA87juxw1Vrh}v{>wb;yHD^; z^U3qR?%KkxjZS~r#cpq$o$T7? zbx&7Q4x~TGe4F(%(;>&j=C9xHwA9_r^OaYg&noX9E*lK4wwbyASi*CPne!4>Mq0l) ze9QX2BI;#aYQnpu@oAlNev4<05iUbrU7V}ijn7}4(JT3J(*Bf*siTsg{XQK%EoyGe zpaie9npw>)t@38eGsaqO?S20Aw|I9ov4do}l~XS7P=2DNXU3$&?6_y~gHkVNp0o6` zE|EF(y9HJ)5>ezr;7j*0j**5+hUJDTvR#&v*fcsk>h$jtDQfzMtm}DCMUHWV zdyH?DK!*_bBJYCsdVVzalSlF^=EvnGXJ#f%k69M^B|0TOEUi*b@BChBSABw0NAJl& zCkp)vtm3=Y<-2}IUQXsc^H1|%=F#cHl0U^Sil39zA!BmxO?9u*MPJdl*!7%`DX3ea z{XRn-Cgoo@ug_SNWyy}o=+2+uQX{X%lt}7oHdyxM^vdjRnP8ag86W(vh>!meW6hjK zDbC3iQ{N<)h`s!+@%wS_)GuL?r(*lZt^WNv`K?8<&vUQiYv=bhpikkW#aowfEP5-r zR>-JgXG*1&dQ(&%=;U?MZM*wxPe-3dK3%+%eU1ja3E5FBwD_yy8O45v%=bU&>FGYr zL+^dgtA*=YL$|z8^We1GsV7riQr0KFjh~<7l@XfNGq=69XWsQpTXL@?UHZgq_uNt0 z+fu&8jQDxtd*t_WKQ4Yxh^YNNI`UBYMk+JZC$K zr-j}XwiR;m-Rw5S`I_@oml;kwbRm|=)U8P;lc%QsOf8w7l%8WgntMaIIox($=DOYO zj>|LqgVuBAk*O|e^)gx9iY0iqg zgSJrXmF)egb(03CoHeh?{c6ilAE`f-v5t;jo`F?@6#oRTb*_EwC#h#GVOeLh;<86) z+h@x3(&=d#$vN&eH>$ar%2~Vi&NaQ}_~v@fa&Buc)jm0^(wve$Cp1r9mr*Oba?XgX z?2O2)zw&3ur^*Q3Fuk8~v-2XiVAs=*$;y?S+bP8o)+hL+RyS`pkIv|jek5&fMrq3u zb+J-WnI~T8KbS(j`uaWeo$9{Su1;PJ^TYI;=3-eR&5o&-gtiHmq(pNI>oRqDerR58 zao+h%V9{cuL&kgEG>)^)%B-BcAntV3#mI>01Hb)}ny37eVoH6S7GgVjJUpC7KjOqtGy-8*~r^62aIpEzpilR3(KFymsXCDAcqR?^*c=j=n4=6UIs z(dI5GZIV7F|HxRJZOcqf*%=oX>G~_@XZv5@e*6fp7hdyclejmjGqPf`%4VnMjI&(K z&Nn~G*lw2C7p6pys_sTnD|GY;ey(mgZQaky%9b(m$`Y1dR= zQ@_OShQnXZGhJRfUNKZq`f>JTalv_>7D`pSxlV;#FSsA^oZ~UlInv%>x5)U#dA7$u zkBu%B9M0*R>2Dam+U>NPsCUq%8@8C%du;U?>-WX`iEDSq!^Tu6llxnboo+)-R^t)7 zt@?4gO!1VrTXU7#j=em}1jwNO0(}Gi@Ez$n)MU_kTf5|!Qk|5y;-@ttdy%qQDZ!zZ&S33qnVMNW)h*%gxGC{2sZFznS~9XLnJZ_cW^S`A&pVU% zAg`LWf!L)Vpzop#QCsExFwadMlGr6B(LC2;%(Ga$a~kI~$R97R>W(Xegh997*x$8~ zM>Th=bDrI6Td$nmnM1NhSwi!3@~&AXXaC4@%KM}aRwn4~D4%ui4zaH5y`OmJxSn@- zq93JR%&C=LCZ$qpGjob%rS)k3Crhi`d$w7+Ji~88fFZ`NkJA>{FK!;D=DM@_?{b!z zJyU-EPLF+%kd*#4cb@veX3k&Cnq!sm`Y*bfx_*YI#y=gW8voKyvFWl3B?ZQ=h8IR-KB*U2f;;vc;>5PbIf$cD;qO&E2vsBR#oDa<%jl7C+fl zsUQw0_3bJ;ly%6pGut;p1Z;n&;V$NhfP> zONOPjYHzp4VUt6Q@v(!&rHprL|Ivj`7OLUD#arj|BJgDKM&&M)|5W;5(cQt5f}4fB zDb&FKnP)ZkY>!#K{R7+sw)<`JIqCV#RcHF?RK{hMYoKdy$A!A)wn3JaS-;Hf(yk^2 zC#EJUsr}4fvyNrfG9NJ8nZKpBNs5XOPq>;|IMX?^L~7mNdm`nJx-LQd7P}9Q-cj%;Svv$m1pL;CpW7?e*bNZ~j&AJ@>PR8v9i~gY9P@~Rq zn`4SYRfiwOqxPYOW}xEnE-BcDd3 ze68{0X?z{a5`DT|9&hsdDsT12?3dYBF~lhey7~@JT>E(q^L6+C;Aiq3;(IYj6dzjF zR3W^qL&-`-Dg@sTiV0ZnyVP^2o5}5$ySLX5ueKhmT$i}1?u*>woQm3avU_I?Gxcp4u>RTkPTJVX-Ok8A*R6`6O5pJ|yXrHz$ruXr1&p{Z@|1-(%UG zz9yk!%)Y3L(W|4|ME(5v=0`}>fz zZu8ud+0D%_GXBl%np@QNNgb~|(;v_;P#i^T-C2iH?wMXEJ-fJmcl=`f+o%|O*;#cB z6kq*S`*bHK*K*D$98IR`E;pS!Iel>GWD4{6;pZFlGvI>vf38lZqE1y!+f92NXW7>@ zEH=C}HZ^s23ULT`d}F#`+T=9Ev7vL4M<3rZ0SSI}J&&618fzKWxtsGf$CeYEvplP6W=2Naj2Y>jQ|2d5OYD?5H2zoI z+W7F)dAXf*jt-?99gTMl$-0aBa64!FJbkFzI`>IVxtyBW6U~LwNVKW3(6mCoHH z_c}E2yx?Cd;EcDA`$v}um+h{FoV(f$ux4etWwcMPmF}D|C;fcN>ZJOqH7%VD;V%Dr zMtjxt-0SwlWwJ}IbH3AEV`JTETSnggY!|aj#^bbU$%PY6Cd^5jmDkJ#uhuC2a$orC0*1S12HT6#F

Z2zBD!0!7jqt)3b@^EZ2&rF;3S_ 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 K6m~vV)Bgv2^wenp literal 0 HcmV?d00001 diff --git a/3rdparty/chromaprint/tests/data/test_stereo_44100.raw b/3rdparty/chromaprint/tests/data/test_stereo_44100.raw new file mode 100644 index 0000000000000000000000000000000000000000..bdcb7754da9444d4f4986cc364988840f25c97af GIT binary patch literal 352800 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 RdV8h)oV;Db(-EE$gL&hF9=O;GE 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 bF0eaPE4F!PO6>2!oY*D7PH{tnyW{=`Zj*rx literal 0 HcmV?d00001 diff --git a/3rdparty/chromaprint/tests/main.cpp b/3rdparty/chromaprint/tests/main.cpp new file mode 100644 index 000000000..7ed0f518e --- /dev/null +++ b/3rdparty/chromaprint/tests/main.cpp @@ -0,0 +1,8 @@ +#include + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/3rdparty/chromaprint/tests/test_api.cpp b/3rdparty/chromaprint/tests/test_api.cpp new file mode 100644 index 000000000..0fb47f9bc --- /dev/null +++ b/3rdparty/chromaprint/tests/test_api.cpp @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include +#include "chromaprint.h" + +using namespace std; + +TEST(API, Test2SilenceFp) +{ + short zeroes[1024]; + fill(zeroes, zeroes + 1024, 0); + + ChromaprintContext *ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_TEST2); + chromaprint_start(ctx, 44100, 1); + for (int i = 0; i < 130; i++) { + chromaprint_feed(ctx, zeroes, 1024); + } + + char *fp; + + chromaprint_finish(ctx); + chromaprint_get_fingerprint(ctx, &fp); + + ASSERT_EQ(18, strlen(fp)); + EXPECT_EQ(string("AQAAA0mUaEkSRZEGAA"), string(fp)); +} + +TEST(API, Test2SilenceRawFp) +{ + short zeroes[1024]; + fill(zeroes, zeroes + 1024, 0); + + ChromaprintContext *ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_TEST2); + chromaprint_start(ctx, 44100, 1); + for (int i = 0; i < 130; i++) { + chromaprint_feed(ctx, zeroes, 1024); + } + + int32_t *fp; + int length; + + chromaprint_finish(ctx); + chromaprint_get_raw_fingerprint(ctx, (void **)&fp, &length); + + ASSERT_EQ(3, length); + EXPECT_EQ(627964279, fp[0]); + EXPECT_EQ(627964279, fp[1]); + EXPECT_EQ(627964279, fp[2]); +} + +TEST(API, TestEncodeFingerprint) +{ + int32_t fingerprint[] = { 1, 0 }; + char expected[] = { 55, 0, 0, 2, 65, 0 }; + + char *encoded; + int encoded_size; + chromaprint_encode_fingerprint(fingerprint, 2, 55, (void **)&encoded, &encoded_size, 0); + + ASSERT_EQ(6, encoded_size); + for (int i = 0; i < encoded_size; i++) { + ASSERT_EQ(expected[i], encoded[i]) << "Different at " << i; + } + + free(encoded); +} + +TEST(API, TestEncodeFingerprintBase64) +{ + int32_t fingerprint[] = { 1, 0 }; + char expected[] = "NwAAAkEA"; + + char *encoded; + int encoded_size; + chromaprint_encode_fingerprint(fingerprint, 2, 55, (void **)&encoded, &encoded_size, 1); + + ASSERT_EQ(8, encoded_size); + ASSERT_STREQ(expected, encoded); + + free(encoded); +} + +TEST(API, TestDecodeFingerprint) +{ + char data[] = { 55, 0, 0, 2, 65, 0 }; + + int32_t *fingerprint; + int size; + int algorithm; + chromaprint_decode_fingerprint(data, 6, (void **)&fingerprint, &size, &algorithm, 0); + + ASSERT_EQ(2, size); + ASSERT_EQ(55, algorithm); + ASSERT_EQ(1, fingerprint[0]); + ASSERT_EQ(0, fingerprint[1]); +} + diff --git a/3rdparty/chromaprint/tests/test_audio_processor.cpp b/3rdparty/chromaprint/tests/test_audio_processor.cpp new file mode 100644 index 000000000..66f271aa8 --- /dev/null +++ b/3rdparty/chromaprint/tests/test_audio_processor.cpp @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include +#include "test_utils.h" +#include "audio_processor.h" +#include "audio_buffer.h" +#include "utils.h" + +using namespace std; +using namespace Chromaprint; + +TEST(AudioProcessor, Accessors) +{ + vector data = LoadAudioFile("data/test_mono_44100.raw"); + + boost::scoped_ptr buffer(new AudioBuffer()); + boost::scoped_ptr buffer2(new AudioBuffer()); + boost::scoped_ptr processor(new AudioProcessor(44100, buffer.get())); + + EXPECT_EQ(44100, processor->target_sample_rate()); + EXPECT_EQ(buffer.get(), processor->consumer()); + + processor->set_target_sample_rate(11025); + EXPECT_EQ(11025, processor->target_sample_rate()); + + processor->set_consumer(buffer2.get()); + EXPECT_EQ(buffer2.get(), processor->consumer()); +} + +TEST(AudioProcessor, PassThrough) +{ + vector data = LoadAudioFile("data/test_mono_44100.raw"); + + boost::scoped_ptr buffer(new AudioBuffer()); + boost::scoped_ptr processor(new AudioProcessor(44100, buffer.get())); + processor->Reset(44100, 1); + processor->Consume(&data[0], data.size()); + processor->Flush(); + + ASSERT_EQ(data.size(), buffer->data().size()); + for (size_t i = 0; i < data.size(); i++) { + ASSERT_EQ(data[i], buffer->data()[i]) << "Signals differ at index " << i; + } +} + +TEST(AudioProcessor, StereoToMono) +{ + vector data1 = LoadAudioFile("data/test_stereo_44100.raw"); + vector data2 = LoadAudioFile("data/test_mono_44100.raw"); + + boost::scoped_ptr buffer(new AudioBuffer()); + boost::scoped_ptr processor(new AudioProcessor(44100, buffer.get())); + processor->Reset(44100, 2); + processor->Consume(&data1[0], data1.size()); + processor->Flush(); + + ASSERT_EQ(data2.size(), buffer->data().size()); + for (size_t i = 0; i < data2.size(); i++) { + ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i; + } +} + +TEST(AudioProcessor, ResampleMono) +{ + vector data1 = LoadAudioFile("data/test_mono_44100.raw"); + vector data2 = LoadAudioFile("data/test_mono_11025.raw"); + + boost::scoped_ptr buffer(new AudioBuffer()); + boost::scoped_ptr processor(new AudioProcessor(11025, buffer.get())); + processor->Reset(44100, 1); + processor->Consume(&data1[0], data1.size()); + processor->Flush(); + + ASSERT_EQ(data2.size(), buffer->data().size()); + for (size_t i = 0; i < data2.size(); i++) { + ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i; + } +} + +TEST(AudioProcessor, ResampleMonoNonInteger) +{ + vector data1 = LoadAudioFile("data/test_mono_44100.raw"); + vector data2 = LoadAudioFile("data/test_mono_8000.raw"); + + boost::scoped_ptr buffer(new AudioBuffer()); + boost::scoped_ptr processor(new AudioProcessor(8000, buffer.get())); + processor->Reset(44100, 1); + processor->Consume(&data1[0], data1.size()); + processor->Flush(); + + ASSERT_EQ(data2.size(), buffer->data().size()); + for (size_t i = 0; i < data2.size(); i++) { + ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i; + } +} + +TEST(AudioProcessor, StereoToMonoAndResample) +{ + vector data1 = LoadAudioFile("data/test_stereo_44100.raw"); + vector data2 = LoadAudioFile("data/test_mono_11025.raw"); + + boost::scoped_ptr buffer(new AudioBuffer()); + boost::scoped_ptr processor(new AudioProcessor(11025, buffer.get())); + processor->Reset(44100, 2); + processor->Consume(&data1[0], data1.size()); + processor->Flush(); + + ASSERT_EQ(data2.size(), buffer->data().size()); + for (size_t i = 0; i < data2.size(); i++) { + ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i; + } +} diff --git a/3rdparty/chromaprint/tests/test_base64.cpp b/3rdparty/chromaprint/tests/test_base64.cpp new file mode 100644 index 000000000..59d0d55a8 --- /dev/null +++ b/3rdparty/chromaprint/tests/test_base64.cpp @@ -0,0 +1,56 @@ +#include +#include "base64.h" +#include "test_utils.h" + +using namespace std; +using namespace Chromaprint; + +TEST(Base64, Base64Encode) +{ + ASSERT_EQ("eA", Base64Encode("x")); + ASSERT_EQ("eHg", Base64Encode("xx")); + ASSERT_EQ("eHh4", Base64Encode("xxx")); + ASSERT_EQ("eHh4eA", Base64Encode("xxxx")); + ASSERT_EQ("eHh4eHg", Base64Encode("xxxxx")); + ASSERT_EQ("eHh4eHh4", Base64Encode("xxxxxx")); + ASSERT_EQ("_-4", Base64Encode("\xff\xee")); +} + +TEST(Base64, Base64Decode) +{ + ASSERT_EQ("x", Base64Decode("eA")); + ASSERT_EQ("xx", Base64Decode("eHg")); + ASSERT_EQ("xxx", Base64Decode("eHh4")); + ASSERT_EQ("xxxx", Base64Decode("eHh4eA")); + ASSERT_EQ("xxxxx", Base64Decode("eHh4eHg")); + ASSERT_EQ("xxxxxx", Base64Decode("eHh4eHh4")); + ASSERT_EQ("\xff\xee", Base64Decode("_-4")); +} + +TEST(Base64, Base64EncodeLong) +{ + char original[] = { + 1, 0, 1, 207, 17, 181, 36, 18, 19, 37, 65, 15, 31, 197, 149, 161, 63, 33, 22, + 60, 141, 27, 202, 35, 184, 47, 254, 227, 135, 135, 11, 58, 139, 208, 65, 127, + 52, 167, 241, 31, 99, 182, 25, 159, 96, 70, 71, 160, 251, 168, 75, 132, 185, + 112, 230, 193, 133, 252, 42, 126, 66, 91, 121, 60, 135, 79, 24, 185, 210, 28, + 199, 133, 255, 240, 113, 101, 67, 199, 23, 225, 181, 160, 121, 140, 67, 123, + 161, 229, 184, 137, 30, 205, 135, 119, 70, 94, 252, 71, 120, 150 + }; + char encoded[] = "AQABzxG1JBITJUEPH8WVoT8hFjyNG8ojuC_-44eHCzqL0EF_NKfxH2O2GZ9gRkeg-6hLhLlw5sGF_Cp-Qlt5PIdPGLnSHMeF__BxZUPHF-G1oHmMQ3uh5biJHs2Hd0Ze_Ed4lg"; + ASSERT_EQ(encoded, Base64Encode(string(original, NELEMS(original)))); +} + +TEST(Base64, Base64DecodeLong) +{ + char original[] = { + 1, 0, 1, 207, 17, 181, 36, 18, 19, 37, 65, 15, 31, 197, 149, 161, 63, 33, 22, + 60, 141, 27, 202, 35, 184, 47, 254, 227, 135, 135, 11, 58, 139, 208, 65, 127, + 52, 167, 241, 31, 99, 182, 25, 159, 96, 70, 71, 160, 251, 168, 75, 132, 185, + 112, 230, 193, 133, 252, 42, 126, 66, 91, 121, 60, 135, 79, 24, 185, 210, 28, + 199, 133, 255, 240, 113, 101, 67, 199, 23, 225, 181, 160, 121, 140, 67, 123, + 161, 229, 184, 137, 30, 205, 135, 119, 70, 94, 252, 71, 120, 150 + }; + char encoded[] = "AQABzxG1JBITJUEPH8WVoT8hFjyNG8ojuC_-44eHCzqL0EF_NKfxH2O2GZ9gRkeg-6hLhLlw5sGF_Cp-Qlt5PIdPGLnSHMeF__BxZUPHF-G1oHmMQ3uh5biJHs2Hd0Ze_Ed4lg"; + ASSERT_EQ(string(original, NELEMS(original)), Base64Decode(string(encoded))); +} diff --git a/3rdparty/chromaprint/tests/test_bit_string_reader.cpp b/3rdparty/chromaprint/tests/test_bit_string_reader.cpp new file mode 100644 index 000000000..9f358e915 --- /dev/null +++ b/3rdparty/chromaprint/tests/test_bit_string_reader.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include "image.h" +#include "classifier.h" +#include "bit_string_reader.h" +#include "utils.h" +#include "test_utils.h" + +using namespace std; +using namespace Chromaprint; + +TEST(BitStringReader, OneByte) +{ + char data[] = { -28 }; + BitStringReader reader(string(data, 1)); + + ASSERT_EQ(0, reader.Read(2)); + ASSERT_EQ(1, reader.Read(2)); + ASSERT_EQ(2, reader.Read(2)); + ASSERT_EQ(3, reader.Read(2)); +} + +TEST(BitStringReader, TwoBytesIncomplete) +{ + char data[] = { -28, 1 }; + BitStringReader reader(string(data, 2)); + + ASSERT_EQ(0, reader.Read(2)); + ASSERT_EQ(1, reader.Read(2)); + ASSERT_EQ(2, reader.Read(2)); + ASSERT_EQ(3, reader.Read(2)); + ASSERT_EQ(1, reader.Read(2)); +} + +TEST(BitStringReader, TwoBytesSplit) +{ + char data[] = { -120, 6 }; + BitStringReader reader(string(data, 2)); + + ASSERT_EQ(0, reader.Read(3)); + ASSERT_EQ(1, reader.Read(3)); + ASSERT_EQ(2, reader.Read(3)); + ASSERT_EQ(3, reader.Read(3)); +} diff --git a/3rdparty/chromaprint/tests/test_bit_string_writer.cpp b/3rdparty/chromaprint/tests/test_bit_string_writer.cpp new file mode 100644 index 000000000..4a54e0534 --- /dev/null +++ b/3rdparty/chromaprint/tests/test_bit_string_writer.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include "image.h" +#include "classifier.h" +#include "bit_string_writer.h" +#include "utils.h" +#include "test_utils.h" + +using namespace std; +using namespace Chromaprint; + +TEST(BitStringWriter, OneByte) +{ + BitStringWriter writer; + writer.Write(0, 2); + writer.Write(1, 2); + writer.Write(2, 2); + writer.Write(3, 2); + writer.Flush(); + + char expected[] = { -28 }; + CheckString(writer.value(), expected, sizeof(expected)/sizeof(expected[0])); +} + +TEST(BitStringWriter, TwoBytesIncomplete) +{ + BitStringWriter writer; + writer.Write(0, 2); + writer.Write(1, 2); + writer.Write(2, 2); + writer.Write(3, 2); + writer.Write(1, 2); + writer.Flush(); + + char expected[] = { -28, 1 }; + CheckString(writer.value(), expected, sizeof(expected)/sizeof(expected[0])); +} + +TEST(BitStringWriter, TwoBytesSplit) +{ + BitStringWriter writer; + writer.Write(0, 3); + writer.Write(1, 3); + writer.Write(2, 3); + writer.Write(3, 3); + writer.Flush(); + + char expected[] = { -120, 6 }; + CheckString(writer.value(), expected, sizeof(expected)/sizeof(expected[0])); +} diff --git a/3rdparty/chromaprint/tests/test_chroma.cpp b/3rdparty/chromaprint/tests/test_chroma.cpp new file mode 100644 index 000000000..6a927a13d --- /dev/null +++ b/3rdparty/chromaprint/tests/test_chroma.cpp @@ -0,0 +1,125 @@ +#include +#include +#include +#include "fft_frame.h" +#include "chroma.h" + +using namespace std; +using namespace Chromaprint; + +class FeatureVectorBuffer : public FeatureVectorConsumer +{ +public: + void Consume(std::vector &features) + { + m_features = features; + } + + std::vector m_features; +}; + +TEST(Chroma, NormalA) { + FeatureVectorBuffer buffer; + Chroma chroma(10, 510, 256, 1000, &buffer); + FFTFrame frame(128); + std::fill(frame.data(), frame.data() + frame.size(), 0.0); + frame.data()[113] = 1.0; + chroma.Consume(frame); + ASSERT_EQ(12, buffer.m_features.size()); + double expected_features[12] = { + 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + }; + for (int i = 0; i < 12; i++) { + EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i; + } +} + +TEST(Chroma, NormalGSharp) { + FeatureVectorBuffer buffer; + Chroma chroma(10, 510, 256, 1000, &buffer); + FFTFrame frame(128); + std::fill(frame.data(), frame.data() + frame.size(), 0.0); + frame.data()[112] = 1.0; + chroma.Consume(frame); + ASSERT_EQ(12, buffer.m_features.size()); + double expected_features[12] = { + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, + }; + for (int i = 0; i < 12; i++) { + EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i; + } +} + +TEST(Chroma, NormalB) { + FeatureVectorBuffer buffer; + Chroma chroma(10, 510, 256, 1000, &buffer); + FFTFrame frame(128); + std::fill(frame.data(), frame.data() + frame.size(), 0.0); + frame.data()[64] = 1.0; // 250 Hz + chroma.Consume(frame); + ASSERT_EQ(12, buffer.m_features.size()); + double expected_features[12] = { + 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + }; + for (int i = 0; i < 12; i++) { + EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i; + } +} + +TEST(Chroma, InterpolatedB) { + FeatureVectorBuffer buffer; + Chroma chroma(10, 510, 256, 1000, &buffer); + chroma.set_interpolate(true); + FFTFrame frame(128); + std::fill(frame.data(), frame.data() + frame.size(), 0.0); + frame.data()[64] = 1.0; + chroma.Consume(frame); + ASSERT_EQ(12, buffer.m_features.size()); + double expected_features[12] = { + 0.0, 0.286905, 0.713095, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + }; + for (int i = 0; i < 12; i++) { + EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i; + } +} + +TEST(Chroma, InterpolatedA) { + FeatureVectorBuffer buffer; + Chroma chroma(10, 510, 256, 1000, &buffer); + chroma.set_interpolate(true); + FFTFrame frame(128); + std::fill(frame.data(), frame.data() + frame.size(), 0.0); + frame.data()[113] = 1.0; + chroma.Consume(frame); + ASSERT_EQ(12, buffer.m_features.size()); + double expected_features[12] = { + 0.555242, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.444758, + }; + for (int i = 0; i < 12; i++) { + EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i; + } +} + +TEST(Chroma, InterpolatedGSharp) { + FeatureVectorBuffer buffer; + Chroma chroma(10, 510, 256, 1000, &buffer); + chroma.set_interpolate(true); + FFTFrame frame(128); + std::fill(frame.data(), frame.data() + frame.size(), 0.0); + frame.data()[112] = 1.0; + chroma.Consume(frame); + ASSERT_EQ(12, buffer.m_features.size()); + double expected_features[12] = { + 0.401354, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.598646, + }; + for (int i = 0; i < 12; i++) { + EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i; + } +} + diff --git a/3rdparty/chromaprint/tests/test_chroma_filter.cpp b/3rdparty/chromaprint/tests/test_chroma_filter.cpp new file mode 100644 index 000000000..b99959dcc --- /dev/null +++ b/3rdparty/chromaprint/tests/test_chroma_filter.cpp @@ -0,0 +1,74 @@ +#include +#include "image.h" +#include "image_builder.h" +#include "chroma_filter.h" + +using namespace std; +using namespace Chromaprint; + +TEST(ChromaFilter, Blur2) { + double coefficients[] = { 0.5, 0.5 }; + Image image(12); + ImageBuilder builder(&image); + ChromaFilter filter(coefficients, 2, &builder); + double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + std::vector v1(d1, d1 + 12); + std::vector v2(d2, d2 + 12); + std::vector v3(d3, d3 + 12); + filter.Consume(v1); + filter.Consume(v2); + filter.Consume(v3); + ASSERT_EQ(2, image.NumRows()); + EXPECT_EQ(0.5, image[0][0]); + EXPECT_EQ(1.5, image[1][0]); + EXPECT_EQ(5.5, image[0][1]); + EXPECT_EQ(6.5, image[1][1]); +} + +TEST(ChromaFilter, Blur3) { + double coefficients[] = { 0.5, 0.7, 0.5 }; + Image image(12); + ImageBuilder builder(&image); + ChromaFilter filter(coefficients, 3, &builder); + double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + double d4[] = { 3.0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + std::vector v1(d1, d1 + 12); + std::vector v2(d2, d2 + 12); + std::vector v3(d3, d3 + 12); + std::vector v4(d4, d4 + 12); + filter.Consume(v1); + filter.Consume(v2); + filter.Consume(v3); + filter.Consume(v4); + ASSERT_EQ(2, image.NumRows()); + EXPECT_FLOAT_EQ(1.7, image[0][0]); + EXPECT_FLOAT_EQ(3.399999999999999, image[1][0]); + EXPECT_FLOAT_EQ(10.199999999999999, image[0][1]); + EXPECT_FLOAT_EQ(11.899999999999999, image[1][1]); +} + +TEST(ChromaFilter, Diff) { + double coefficients[] = { 1.0, -1.0 }; + Image image(12); + ImageBuilder builder(&image); + ChromaFilter filter(coefficients, 2, &builder); + double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + std::vector v1(d1, d1 + 12); + std::vector v2(d2, d2 + 12); + std::vector v3(d3, d3 + 12); + filter.Consume(v1); + filter.Consume(v2); + filter.Consume(v3); + ASSERT_EQ(2, image.NumRows()); + EXPECT_EQ(-1.0, image[0][0]); + EXPECT_EQ(-1.0, image[1][0]); + EXPECT_EQ(-1.0, image[0][1]); + EXPECT_EQ(-1.0, image[1][1]); +} + diff --git a/3rdparty/chromaprint/tests/test_chroma_resampler.cpp b/3rdparty/chromaprint/tests/test_chroma_resampler.cpp new file mode 100644 index 000000000..f7eeb833e --- /dev/null +++ b/3rdparty/chromaprint/tests/test_chroma_resampler.cpp @@ -0,0 +1,48 @@ +#include +#include "image.h" +#include "image_builder.h" +#include "chroma_resampler.h" + +using namespace std; +using namespace Chromaprint; + +TEST(ChromaResampler, Test1) { + Image image(12); + ImageBuilder builder(&image); + ChromaResampler resampler(2, &builder); + double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + std::vector v1(d1, d1 + 12); + std::vector v2(d2, d2 + 12); + std::vector v3(d3, d3 + 12); + resampler.Consume(v1); + resampler.Consume(v2); + resampler.Consume(v3); + ASSERT_EQ(1, image.NumRows()); + EXPECT_EQ(0.5, image[0][0]); + EXPECT_EQ(5.5, image[0][1]); +} + +TEST(ChromaResampler, Test2) { + Image image(12); + ImageBuilder builder(&image); + ChromaResampler resampler(2, &builder); + double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + double d4[] = { 3.0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + std::vector v1(d1, d1 + 12); + std::vector v2(d2, d2 + 12); + std::vector v3(d3, d3 + 12); + std::vector v4(d4, d4 + 12); + resampler.Consume(v1); + resampler.Consume(v2); + resampler.Consume(v3); + resampler.Consume(v4); + ASSERT_EQ(2, image.NumRows()); + EXPECT_EQ(0.5, image[0][0]); + EXPECT_EQ(5.5, image[0][1]); + EXPECT_EQ(2.5, image[1][0]); + EXPECT_EQ(7.5, image[1][1]); +} diff --git a/3rdparty/chromaprint/tests/test_chromaprint.cpp b/3rdparty/chromaprint/tests/test_chromaprint.cpp new file mode 100644 index 000000000..26fe7120b --- /dev/null +++ b/3rdparty/chromaprint/tests/test_chromaprint.cpp @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include "audio_processor.h" +#include "test_utils.h" +#include "audio_processor.h" +#include "chroma.h" +#include "chroma_normalizer.h" +#include "chroma_resampler.h" +#include "fft.h" +#include "audio_processor.h" +#include "image.h" +#include "image_builder.h" +#include "utils.h" + +using namespace std; +using namespace Chromaprint; + +static const int SAMPLE_RATE = 11025; +static const int FRAME_SIZE = 4096; +static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720; +static const int MIN_FREQ = 28; +static const int MAX_FREQ = 3520; +static const int MAX_FILTER_WIDTH = 20; + +TEST(Chromaprint, BasicImage) +{ + vector data = LoadAudioFile("data/test_stereo_44100.raw"); + + Chromaprint::Image image(12); + Chromaprint::ImageBuilder image_builder(&image); + Chromaprint::ChromaNormalizer chroma_normalizer(&image_builder); + Chromaprint::Chroma chroma(MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &chroma_normalizer); + Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, &chroma); + Chromaprint::AudioProcessor processor(SAMPLE_RATE, &fft); + + processor.Reset(44100, 2); + processor.Consume(&data[0], data.size()); + processor.Flush(); + + double chromagram[][12] = { + { 0.155444, 0.268618, 0.474445, 0.159887, 0.1761, 0.423511, 0.178933, 0.34433, 0.360958, 0.30421, 0.200217, 0.17072 }, + { 0.159809, 0.238675, 0.286526, 0.166119, 0.225144, 0.449236, 0.162444, 0.371875, 0.259626, 0.483961, 0.24491, 0.17034 }, + { 0.156518, 0.271503, 0.256073, 0.152689, 0.174664, 0.52585, 0.141517, 0.253695, 0.293199, 0.332114, 0.442906, 0.170459 }, + { 0.154183, 0.38592, 0.497451, 0.203884, 0.362608, 0.355691, 0.125349, 0.146766, 0.315143, 0.318133, 0.172547, 0.112769 }, + { 0.201289, 0.42033, 0.509467, 0.259247, 0.322772, 0.325837, 0.140072, 0.177756, 0.320356, 0.228176, 0.148994, 0.132588 }, + { 0.187921, 0.302804, 0.46976, 0.302809, 0.183035, 0.228691, 0.206216, 0.35174, 0.308208, 0.233234, 0.316017, 0.243563 }, + { 0.213539, 0.240346, 0.308664, 0.250704, 0.204879, 0.365022, 0.241966, 0.312579, 0.361886, 0.277293, 0.338944, 0.290351 }, + { 0.227784, 0.252841, 0.295752, 0.265796, 0.227973, 0.451155, 0.219418, 0.272508, 0.376082, 0.312717, 0.285395, 0.165745 }, + { 0.168662, 0.180795, 0.264397, 0.225101, 0.562332, 0.33243, 0.236684, 0.199847, 0.409727, 0.247569, 0.21153, 0.147286 }, + { 0.0491864, 0.0503369, 0.130942, 0.0505802, 0.0694409, 0.0303877, 0.0389852, 0.674067, 0.712933, 0.05762, 0.0245158, 0.0389336 }, + { 0.0814379, 0.0312366, 0.240546, 0.134609, 0.063374, 0.0466124, 0.0752175, 0.657041, 0.680085, 0.0720311, 0.0249404, 0.0673359 }, + { 0.139331, 0.0173442, 0.49035, 0.287237, 0.0453947, 0.0873279, 0.15423, 0.447475, 0.621502, 0.127166, 0.0355933, 0.141163 }, + { 0.115417, 0.0132515, 0.356601, 0.245902, 0.0283943, 0.0588233, 0.117077, 0.499376, 0.715366, 0.100398, 0.0281382, 0.0943482 }, + { 0.047297, 0.0065354, 0.181074, 0.121455, 0.0135504, 0.030693, 0.0613105, 0.631705, 0.73548, 0.0550565, 0.0128093, 0.0460393 }, + }; + + ASSERT_EQ(14, image.NumRows()) << "Numbers of rows doesn't match"; + for (int y = 0; y < 14; y++) { + for (int x = 0; x < 12; x++) { + EXPECT_NEAR(chromagram[y][x], image[y][x], 1e-5) + << "Image not equal at (" << x << ", " << y << ")"; + } + } +} diff --git a/3rdparty/chromaprint/tests/test_combined_buffer.cpp b/3rdparty/chromaprint/tests/test_combined_buffer.cpp new file mode 100644 index 000000000..cfc17bd73 --- /dev/null +++ b/3rdparty/chromaprint/tests/test_combined_buffer.cpp @@ -0,0 +1,95 @@ +#include +#include +#include "combined_buffer.h" + +using namespace std; +using namespace Chromaprint; + +TEST(CombinedBuffer, Size) { + short buffer1[] = { 1, 2, 3, 4, 5 }; + short buffer2[] = { 6, 7, 8 }; + CombinedBuffer buffer(buffer1, 5, buffer2, 3); + EXPECT_EQ(8, buffer.Size()); + buffer.Shift(1); + EXPECT_EQ(7, buffer.Size()); +} + +TEST(CombinedBuffer, AccessElements) { + short buffer1[] = { 1, 2, 3, 4, 5 }; + short buffer2[] = { 6, 7, 8 }; + CombinedBuffer buffer(buffer1, 5, buffer2, 3); + for (int i = 0; i < 8; i++) { + EXPECT_EQ(1 + i, buffer[i]); + } + buffer.Shift(1); + for (int i = 0; i < 7; i++) { + EXPECT_EQ(2 + i, buffer[i]); + } + buffer.Shift(5); + for (int i = 0; i < 2; i++) { + EXPECT_EQ(7 + i, buffer[i]); + } +} + +TEST(CombinedBuffer, AccessElementsViaIterator) { + short buffer1[] = { 1, 2, 3, 4, 5 }; + short buffer2[] = { 6, 7, 8 }; + CombinedBuffer buffer(buffer1, 5, buffer2, 3); + CombinedBuffer::Iterator iter = buffer.Begin(); + for (int i = 0; i < 8; i++) { + EXPECT_EQ(1 + i, *iter); + ++iter; + } + EXPECT_TRUE(buffer.End() == iter); +} + +TEST(CombinedBuffer, AccessElementsViaIteratorAfterShift) { + short buffer1[] = { 1, 2, 3, 4, 5 }; + short buffer2[] = { 6, 7, 8 }; + CombinedBuffer buffer(buffer1, 5, buffer2, 3); + buffer.Shift(6); + CombinedBuffer::Iterator iter = buffer.Begin(); + for (int i = 0; i < 2; i++) { + EXPECT_EQ(7 + i, *iter); + ++iter; + } + EXPECT_TRUE(buffer.End() == iter); +} + +TEST(CombinedBuffer, CopyUsingStlAlgorithms) { + short buffer1[] = { 1, 2, 3, 4, 5 }; + short buffer2[] = { 6, 7, 8 }; + short tmp[10]; + CombinedBuffer buffer(buffer1, 5, buffer2, 3); + fill(tmp, tmp + 10, 0); + for (int i = 0; i < 10; i++) { + EXPECT_EQ(0, tmp[i]); + } + copy(buffer.Begin(), buffer.End(), tmp); + for (int i = 0; i < 8; i++) { + EXPECT_EQ(1 + i, tmp[i]); + } + for (int i = 8; i < 10; i++) { + EXPECT_EQ(0, tmp[i]); + } +} + +TEST(CombinedBuffer, CopyUsingStlAlgorithmsAfterShift) { + short buffer1[] = { 1, 2, 3, 4, 5 }; + short buffer2[] = { 6, 7, 8 }; + short tmp[10]; + CombinedBuffer buffer(buffer1, 5, buffer2, 3); + buffer.Shift(6); + fill(tmp, tmp + 10, 0); + for (int i = 0; i < 10; i++) { + EXPECT_EQ(0, tmp[i]); + } + copy(buffer.Begin(), buffer.End(), tmp); + for (int i = 0; i < 2; i++) { + EXPECT_EQ(7 + i, tmp[i]); + } + for (int i = 2; i < 10; i++) { + EXPECT_EQ(0, tmp[i]); + } +} + diff --git a/3rdparty/chromaprint/tests/test_filter.cpp b/3rdparty/chromaprint/tests/test_filter.cpp new file mode 100644 index 000000000..e99a42fc5 --- /dev/null +++ b/3rdparty/chromaprint/tests/test_filter.cpp @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include +#include "image.h" +#include "filter.h" + +using namespace std; +using namespace Chromaprint; + +TEST(Filter, Filter0) +{ + Image image(2, 2); + image[0][0] = 0.0; + image[0][1] = 1.0; + image[1][0] = 2.0; + image[1][1] = 3.0; + + Filter flt1(0, 0, 1, 1); + IntegralImage integral_image(&image); + ASSERT_FLOAT_EQ(0.0, flt1.Apply(&integral_image, 0)); + ASSERT_FLOAT_EQ(1.0986123, flt1.Apply(&integral_image, 1)); +} + diff --git a/3rdparty/chromaprint/tests/test_filter_utils.cpp b/3rdparty/chromaprint/tests/test_filter_utils.cpp new file mode 100644 index 000000000..e1192918f --- /dev/null +++ b/3rdparty/chromaprint/tests/test_filter_utils.cpp @@ -0,0 +1,118 @@ +#include +#include "filter_utils.h" + +using namespace std; +using namespace Chromaprint; + +TEST(FilterUtils, CompareSubtract) { + double res = Subtract(2.0, 1.0); + EXPECT_FLOAT_EQ(1.0, res); +} + +TEST(FilterUtils, CompareSubtractLog) { + double res = SubtractLog(2.0, 1.0); + EXPECT_FLOAT_EQ(0.4054651, res); +} + +TEST(FilterUtils, Filter0) { + double data[] = { + 1.0, 2.0, 3.0, + 4.0, 5.0, 6.0, + 7.0, 8.0, 9.0, + }; + Image image(3, data, data + 9); + IntegralImage integral_image(&image); + double res; + res = Filter0(&integral_image, 0, 0, 1, 1, Subtract); + EXPECT_FLOAT_EQ(1.0, res); + res = Filter0(&integral_image, 0, 0, 2, 2, Subtract); + EXPECT_FLOAT_EQ(12.0, res); + res = Filter0(&integral_image, 0, 0, 3, 3, Subtract); + EXPECT_FLOAT_EQ(45.0, res); + res = Filter0(&integral_image, 1, 1, 2, 2, Subtract); + EXPECT_FLOAT_EQ(28.0, res); + res = Filter0(&integral_image, 2, 2, 1, 1, Subtract); + EXPECT_FLOAT_EQ(9.0, res); + res = Filter0(&integral_image, 0, 0, 3, 1, Subtract); + EXPECT_FLOAT_EQ(12.0, res); + res = Filter0(&integral_image, 0, 0, 1, 3, Subtract); + EXPECT_FLOAT_EQ(6.0, res); +} + +TEST(FilterUtils, Filter1) { + double data[] = { + 1.0, 2.0, 3.0, + 3.0, 4.0, 5.0, + 6.0, 7.0, 8.0, + }; + Image image(3, data, data + 9); + IntegralImage integral_image(&image); + double res; + res = Filter1(&integral_image, 0, 0, 1, 1, Subtract); + EXPECT_FLOAT_EQ(1.0, res); // 2 - 1 + res = Filter1(&integral_image, 0, 0, 2, 2, Subtract); + EXPECT_FLOAT_EQ(2.0, res); // 2+4 - 1+3 + res = Filter1(&integral_image, 0, 0, 3, 2, Subtract); + EXPECT_FLOAT_EQ(3.0, res); // 2+4+7 - 1+3+6 +} + +TEST(FilterUtils, Filter2) { + double data[] = { + 1.0, 2.0, 3.0, + 3.0, 4.0, 5.0, + 6.0, 7.0, 8.0, + }; + Image image(3, data, data + 9); + IntegralImage integral_image(&image); + double res; + res = Filter2(&integral_image, 0, 0, 2, 1, Subtract); + EXPECT_FLOAT_EQ(2.0, res); // 3 - 1 + res = Filter2(&integral_image, 0, 0, 2, 2, Subtract); + EXPECT_FLOAT_EQ(4.0, res); // 3+4 - 1+2 + res = Filter2(&integral_image, 0, 0, 2, 3, Subtract); + EXPECT_FLOAT_EQ(6.0, res); // 3+4+5 - 1+2+3 +} + +TEST(FilterUtils, Filter3) { + double data[] = { + 1.0, 2.1, 3.4, + 3.1, 4.1, 5.1, + 6.0, 7.1, 8.0, + }; + Image image(3, data, data + 9); + IntegralImage integral_image(&image); + double res; + res = Filter3(&integral_image, 0, 0, 2, 2, Subtract); + EXPECT_FLOAT_EQ(0.1, res); // 2.1+3.1 - 1+4.1 + res = Filter3(&integral_image, 1, 1, 2, 2, Subtract); + EXPECT_FLOAT_EQ(0.1, res); // 4+8 - 5+7 + res = Filter3(&integral_image, 0, 1, 2, 2, Subtract); + EXPECT_FLOAT_EQ(0.3, res); // 2.1+5.1 - 3.4+4.1 +} + +TEST(FilterUtils, Filter4) { + double data[] = { + 1.0, 2.0, 3.0, + 3.0, 4.0, 5.0, + 6.0, 7.0, 8.0, + }; + Image image(3, data, data + 9); + IntegralImage integral_image(&image); + double res; + res = Filter4(&integral_image, 0, 0, 3, 3, Subtract); + EXPECT_FLOAT_EQ(-13.0, res); // 2+4+7 - (1+3+6) - (3+5+8) +} + +TEST(FilterUtils, Filter5) { + double data[] = { + 1.0, 2.0, 3.0, + 3.0, 4.0, 5.0, + 6.0, 7.0, 8.0, + }; + Image image(3, data, data + 9); + IntegralImage integral_image(&image); + double res; + res = Filter5(&integral_image, 0, 0, 3, 3, Subtract); + EXPECT_FLOAT_EQ(-15.0, res); // 3+4+5 - (1+2+3) - (6+7+8) +} + diff --git a/3rdparty/chromaprint/tests/test_fingerprint_calculator.cpp b/3rdparty/chromaprint/tests/test_fingerprint_calculator.cpp new file mode 100644 index 000000000..dbce20000 --- /dev/null +++ b/3rdparty/chromaprint/tests/test_fingerprint_calculator.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include "image.h" +#include "classifier.h" +#include "fingerprint_calculator.h" +#include "utils.h" + +using namespace std; +using namespace Chromaprint; + +TEST(FingerprintCalculator, CalculateSubfingerprint) +{ + Image image(2, 2); + image[0][0] = 0.0; + image[0][1] = 1.0; + image[1][0] = 2.0; + image[1][1] = 3.0; + + Classifier classifiers[] = { + Classifier(Filter(0, 0, 1, 1), Quantizer(0.01, 1.01, 1.5)), + }; + FingerprintCalculator calculator(classifiers, 1); + + IntegralImage integral_image(&image); + EXPECT_EQ(GrayCode(0), calculator.CalculateSubfingerprint(&integral_image, 0)); + EXPECT_EQ(GrayCode(2), calculator.CalculateSubfingerprint(&integral_image, 1)); +} + +TEST(FingerprintCalculator, Calculate) +{ + Image image(2, 3); + image[0][0] = 0.0; + image[0][1] = 1.0; + image[1][0] = 2.0; + image[1][1] = 3.0; + image[2][0] = 4.0; + image[2][1] = 5.0; + + Classifier classifiers[] = { + Classifier(Filter(0, 0, 1, 1), Quantizer(0.01, 1.01, 1.5)), + }; + FingerprintCalculator calculator(classifiers, 1); + + vector fp = calculator.Calculate(&image); + ASSERT_EQ(3, fp.size()); + EXPECT_EQ(GrayCode(0), fp[0]); + EXPECT_EQ(GrayCode(2), fp[1]); + EXPECT_EQ(GrayCode(3), fp[2]); +} + diff --git a/3rdparty/chromaprint/tests/test_fingerprint_compressor.cpp b/3rdparty/chromaprint/tests/test_fingerprint_compressor.cpp new file mode 100644 index 000000000..c130ebfbe --- /dev/null +++ b/3rdparty/chromaprint/tests/test_fingerprint_compressor.cpp @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include "image.h" +#include "classifier.h" +#include "fingerprint_compressor.h" +#include "utils.h" +#include "test_utils.h" + +using namespace std; +using namespace Chromaprint; + +TEST(FingerprintCompressor, OneItemOneBit) +{ + FingerprintCompressor compressor; + + int32_t fingerprint[] = { 1 }; + string value = compressor.Compress(vector(fingerprint, fingerprint + 1)); + + char expected[] = { 0, 0, 0, 1, 1 }; + CheckString(value, expected, sizeof(expected)/sizeof(expected[0])); +} + +TEST(FingerprintCompressor, OneItemThreeBits) +{ + FingerprintCompressor compressor; + + int32_t fingerprint[] = { 7 }; + string value = compressor.Compress(vector(fingerprint, fingerprint + 1)); + + char expected[] = { 0, 0, 0, 1, 73, 0 }; + CheckString(value, expected, sizeof(expected)/sizeof(expected[0])); +} + +TEST(FingerprintCompressor, OneItemOneBitExcept) +{ + FingerprintCompressor compressor; + + int32_t fingerprint[] = { 1<<6 }; + string value = compressor.Compress(vector(fingerprint, fingerprint + 1)); + + char expected[] = { 0, 0, 0, 1, 7, 0 }; + CheckString(value, expected, sizeof(expected)/sizeof(expected[0])); +} + +TEST(FingerprintCompressor, OneItemOneBitExcept2) +{ + FingerprintCompressor compressor; + + int32_t fingerprint[] = { 1<<8 }; + string value = compressor.Compress(vector(fingerprint, fingerprint + 1)); + + char expected[] = { 0, 0, 0, 1, 7, 2 }; + CheckString(value, expected, sizeof(expected)/sizeof(expected[0])); +} + +TEST(FingerprintCompressor, TwoItems) +{ + FingerprintCompressor compressor; + + int32_t fingerprint[] = { 1, 0 }; + string value = compressor.Compress(vector(fingerprint, fingerprint + 2)); + + char expected[] = { 0, 0, 0, 2, 65, 0 }; + CheckString(value, expected, sizeof(expected)/sizeof(expected[0])); +} + +TEST(FingerprintCompressor, TwoItemsNoChange) +{ + FingerprintCompressor compressor; + + int32_t fingerprint[] = { 1, 1 }; + string value = compressor.Compress(vector(fingerprint, fingerprint + 2)); + + char expected[] = { 0, 0, 0, 2, 1, 0 }; + CheckString(value, expected, sizeof(expected)/sizeof(expected[0])); +} diff --git a/3rdparty/chromaprint/tests/test_fingerprint_decompressor.cpp b/3rdparty/chromaprint/tests/test_fingerprint_decompressor.cpp new file mode 100644 index 000000000..98d77d6b1 --- /dev/null +++ b/3rdparty/chromaprint/tests/test_fingerprint_decompressor.cpp @@ -0,0 +1,77 @@ +#include +#include +#include +#include "fingerprint_decompressor.h" +#include "utils.h" +#include "test_utils.h" + +using namespace std; +using namespace Chromaprint; + +TEST(FingerprintDecompressor, OneItemOneBit) +{ + int32_t expected[] = { 1 }; + char data[] = { 0, 0, 0, 1, 1 }; + + int algorithm = 1; + vector value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm); + CheckFingerprints(value, expected, NELEMS(expected)); + ASSERT_EQ(0, algorithm); +} + + +TEST(FingerprintDecompressor, OneItemThreeBits) +{ + int32_t expected[] = { 7 }; + char data[] = { 0, 0, 0, 1, 73, 0 }; + + int algorithm = 1; + vector value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm); + CheckFingerprints(value, expected, NELEMS(expected)); + ASSERT_EQ(0, algorithm); +} + +TEST(FingerprintDecompressor, OneItemOneBitExcept) +{ + int32_t expected[] = { 1<<6 }; + char data[] = { 0, 0, 0, 1, 7, 0 }; + + int algorithm = 1; + vector value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm); + CheckFingerprints(value, expected, NELEMS(expected)); + ASSERT_EQ(0, algorithm); +} + +TEST(FingerprintDecompressor, OneItemOneBitExcept2) +{ + int32_t expected[] = { 1<<8 }; + char data[] = { 0, 0, 0, 1, 7, 2 }; + + int algorithm = 1; + vector value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm); + CheckFingerprints(value, expected, NELEMS(expected)); + ASSERT_EQ(0, algorithm); +} + +TEST(FingerprintDecompressor, TwoItems) +{ + int32_t expected[] = { 1, 0 }; + char data[] = { 0, 0, 0, 2, 65, 0 }; + + int algorithm = 1; + vector value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm); + CheckFingerprints(value, expected, NELEMS(expected)); + ASSERT_EQ(0, algorithm); +} + +TEST(FingerprintDecompressor, TwoItemsNoChange) +{ + int32_t expected[] = { 1, 1 }; + char data[] = { 0, 0, 0, 2, 1, 0 }; + + int algorithm = 1; + vector value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm); + CheckFingerprints(value, expected, NELEMS(expected)); + ASSERT_EQ(0, algorithm); +} + diff --git a/3rdparty/chromaprint/tests/test_integral_image.cpp b/3rdparty/chromaprint/tests/test_integral_image.cpp new file mode 100644 index 000000000..bb9a97985 --- /dev/null +++ b/3rdparty/chromaprint/tests/test_integral_image.cpp @@ -0,0 +1,40 @@ +#include +#include "integral_image.h" + +using namespace std; +using namespace Chromaprint; + +TEST(IntegralImage, Basic2D) { + double data[] = { + 1.0, 2.0, + 3.0, 4.0, + }; + Image image(2, data, data + 4); + IntegralImage integral_image(&image); + EXPECT_FLOAT_EQ(1.0, integral_image[0][0]); + EXPECT_FLOAT_EQ(3.0, integral_image[0][1]); + EXPECT_FLOAT_EQ(4.0, integral_image[1][0]); + EXPECT_FLOAT_EQ(10.0, integral_image[1][1]); +} + +TEST(IntegralImage, Vertical1D) { + double data[] = { + 1.0, 2.0, 3.0 + }; + Image image(1, data, data + 3); + IntegralImage integral_image(&image); + EXPECT_FLOAT_EQ(1.0, integral_image[0][0]); + EXPECT_FLOAT_EQ(3.0, integral_image[1][0]); + EXPECT_FLOAT_EQ(6.0, integral_image[2][0]); +} + +TEST(IntegralImage, Horizontal1D) { + double data[] = { + 1.0, 2.0, 3.0 + }; + Image image(3, data, data + 3); + IntegralImage integral_image(&image); + EXPECT_FLOAT_EQ(1.0, integral_image[0][0]); + EXPECT_FLOAT_EQ(3.0, integral_image[0][1]); + EXPECT_FLOAT_EQ(6.0, integral_image[0][2]); +} diff --git a/3rdparty/chromaprint/tests/test_lloyds.cpp b/3rdparty/chromaprint/tests/test_lloyds.cpp new file mode 100644 index 000000000..9fe2297f8 --- /dev/null +++ b/3rdparty/chromaprint/tests/test_lloyds.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include "lloyds.h" + +using namespace std; + +template +ostream &operator<<(ostream &stream, const vector &vec) +{ + for (int i = 0; i < vec.size(); i++) { + if (i != 0) + stream << ", "; + stream << vec[i]; + } + return stream; +} + +/*TEST(Lloyds, Long) { + double signal[] = { + -2.23622, -2.2133, -2.08922, -2.02973, -2.01912, -2.00194, -1.94793, -1.92903, -1.90671, -1.90311, -1.86394, -1.82542, -1.82281, -1.77955, -1.77286, -1.77119, -1.76317, -1.74447, -1.74447, -1.71927, -1.71244, -1.70758, -1.69632, -1.69448, -1.68845, -1.68842, -1.65839, -1.64934, -1.63575, -1.61216, -1.56943, -1.56546, -1.5601, -1.5584, -1.53875, -1.52408, -1.51576, -1.47345, -1.44838, -1.44712, -1.43751, -1.43722, -1.43159, -1.41818, -1.41585, -1.36654, -1.36556, -1.36486, -1.3596, -1.35941, -1.35301, -1.35301, -1.35145, -1.34479, -1.34443, -1.3441, -1.3381, -1.3334, -1.31715, -1.31105, -1.31071, -1.30166, -1.29944, -1.29715, -1.29669, -1.29634, -1.28696, -1.28504, -1.27143, -1.26548, -1.26533, -1.26421, -1.26054, -1.25978, -1.25631, -1.24751, -1.23887, -1.23797, -1.23588, -1.22391, -1.21961, -1.21559, -1.21499, -1.19502, -1.19009, -1.18784, -1.18746, -1.18264, -1.17917, -1.17597, -1.17482, -1.1664, -1.15644, -1.15584, -1.15317, -1.14694, -1.14341, -1.14246, -1.14234, -1.14027, -1.13955, -1.13745, -1.13674, -1.12764, -1.12735, -1.12729, -1.12645, -1.12578, -1.12533, -1.12131, -1.11019, -1.10879, -1.10357, -1.09973, -1.09187, -1.09187, -1.06664, -1.06356, -1.0554, -1.0492, -1.04506, -1.04027, -1.03942, -1.03896, -1.034, -1.03285, -1.02334, -1.02084, -1.01993, -1.01447, -1.01447, -1.01447, -1.00864, -1.00689, -1.00471, -1.00125, -0.999809, -0.998627, -0.998156, -0.994751, -0.994212, -0.993412, -0.992572, -0.992572, -0.992548, -0.992472, -0.989607, -0.987201, -0.982932, -0.982652, -0.980823, -0.976318, -0.974594, -0.973334, -0.97326, -0.971969, -0.970954, -0.964969, -0.963816, -0.960578, -0.959536, -0.95708, -0.953791, -0.953782, -0.952128, -0.951757, -0.95172, -0.951264, -0.950896, -0.949007, -0.947225, -0.945958, -0.945852, -0.945044, -0.94482, -0.940381, -0.940254, -0.940084, -0.939844, -0.937978, -0.935127, -0.93345, -0.931299, -0.931147, -0.929513, -0.927091, -0.926682, -0.926458, -0.925325, -0.918487, -0.917891, -0.917015, -0.916352, -0.915526, -0.915489, -0.913747, -0.91204, -0.911457, -0.911281, -0.910753, -0.909806, -0.909361, -0.908686, -0.907, -0.906509, -0.903637, -0.902177, -0.896958, -0.896304, -0.895733, -0.889965, -0.886484, -0.884943, -0.882143, -0.879831, -0.879507, -0.876134, -0.875782, -0.873226, -0.873167, -0.872282, -0.870152, -0.869655, -0.869655, -0.866992, -0.862656, -0.862331, -0.861969, -0.861246, -0.856819, -0.854323, -0.853294, -0.846832, -0.843682, -0.842113, -0.840478, -0.835353, -0.83055, -0.828979, -0.828979, -0.828088, -0.826904, -0.826844, -0.826474, -0.820101, -0.819027, -0.819027, -0.818121, -0.812784, -0.812206, -0.810112, -0.806803, -0.805296, -0.80126, -0.800501, -0.798129, -0.797067, -0.786663, -0.785991, -0.784662, -0.78212, -0.776524, -0.774306, -0.772335, -0.771675, -0.771675, -0.77125, -0.770083, -0.769165, -0.767499, -0.766419, -0.763909, -0.762582, -0.76243, -0.761753, -0.761182, -0.759494, -0.755514, -0.745122, -0.742554, -0.739007, -0.73575, -0.735359, -0.73376, -0.732161, -0.728712, -0.726951, -0.726218, -0.725935, -0.724686, -0.722143, -0.722044, -0.721563, -0.721248, -0.720543, -0.719718, -0.716511, -0.714431, -0.714329, -0.712779, -0.712512, -0.712512, -0.711802, -0.71157, -0.709608, -0.706909, -0.706774, -0.704839, -0.703444, -0.702687, -0.70263, -0.702272, -0.700726, -0.700691, -0.700566, -0.698961, -0.697583, -0.697153, -0.696813, -0.696062, -0.695309, -0.694557, -0.691675, -0.691434, -0.687548, -0.686447, -0.684052, -0.68283, -0.682705, -0.682523, -0.682514, -0.679172, -0.675747, -0.675161, -0.673046, -0.670132, -0.663973, -0.659537, -0.655187, -0.65481, -0.653818, -0.65335, -0.653181, -0.649845, -0.649723, -0.648533, -0.647648, -0.645932, -0.645885, -0.645736, -0.643418, -0.642324, -0.642275, -0.641053, -0.641053, -0.636907, -0.635015, -0.634658, -0.632863, -0.629322, -0.629234, -0.628869, -0.627114, -0.626578, -0.626576, -0.62511, -0.625091, -0.621436, -0.620774, -0.616916, -0.616051, -0.612722, -0.611527, -0.610163, -0.609325, -0.606185, -0.606169, -0.606019, -0.603731, -0.602434, -0.596665, -0.596236, -0.595822, -0.594053, -0.588736, -0.588164, -0.586796, -0.586709, -0.585038, -0.583978, -0.583929, -0.582533, -0.576205, -0.57511 + }; + vector r = lloyds(signal, signal + sizeof(signal) / sizeof(signal[0]), 10); + EXPECT_EQ(9, r.size()); + EXPECT_FLOAT_EQ(-2.15126, r[0]); + EXPECT_FLOAT_EQ(-1.95019, r[1]); + EXPECT_FLOAT_EQ(-1.72034, r[2]); + EXPECT_FLOAT_EQ(-1.42570, r[3]); + EXPECT_FLOAT_EQ(-1.23976, r[4]); + EXPECT_FLOAT_EQ(-1.06092, r[5]); + EXPECT_FLOAT_EQ(-0.93395, r[6]); + EXPECT_FLOAT_EQ(-0.81530, r[7]); + EXPECT_FLOAT_EQ(-0.68837, r[8]); +}*/ + +TEST(LLoyds, Lloyds1) { + double data[] = { + 1.0, 1.1, 1.2, + 3.0, 3.1, 3.2, + }; + vector sig(data, data + 6); + vector table = lloyds(sig, 2); + EXPECT_EQ(1, table.size()); + EXPECT_FLOAT_EQ(2.1, table[0]); +} + +TEST(LLoyds, Lloyds2) { + double data[] = { + 1.0, 1.1, 1.2, + }; + vector sig(data, data + 3); + vector table = lloyds(sig, 2); + EXPECT_EQ(1, table.size()); + EXPECT_FLOAT_EQ(1.075, table[0]); +} + +TEST(LLoyds, Lloyds3) { + double data[] = { + 1.0, 1.1, 1.2, + }; + vector sig(data, data + 3); + vector table = lloyds(sig, 3); + EXPECT_EQ(2, table.size()); + EXPECT_FLOAT_EQ(1.05, table[0]); + EXPECT_FLOAT_EQ(1.15, table[1]); +} + +TEST(LLoyds, Lloyds4) { + double data[] = { + 435,219,891,906,184,572,301,892,875,121,245,146,640,137,938,25,668,288,848,790,141,890,528,145,289,861,339,769,293,757 + }; + vector sig(data, data + 30); + vector table = lloyds(sig, 4); + EXPECT_EQ(3, table.size()); + EXPECT_FLOAT_EQ(214.77678, table[0]); + EXPECT_FLOAT_EQ(451.5625, table[1]); + EXPECT_FLOAT_EQ(729.04547, table[2]); +} + + diff --git a/3rdparty/chromaprint/tests/test_quantizer.cpp b/3rdparty/chromaprint/tests/test_quantizer.cpp new file mode 100644 index 000000000..68f176922 --- /dev/null +++ b/3rdparty/chromaprint/tests/test_quantizer.cpp @@ -0,0 +1,17 @@ +#include +#include "quantizer.h" + +using namespace std; +using namespace Chromaprint; + +TEST(Quantizer, Quantize) { + Quantizer q(0.0, 0.1, 0.3); + EXPECT_EQ(0, q.Quantize(-0.1)); + EXPECT_EQ(1, q.Quantize(0.0)); + EXPECT_EQ(1, q.Quantize(0.03)); + EXPECT_EQ(2, q.Quantize(0.1)); + EXPECT_EQ(2, q.Quantize(0.13)); + EXPECT_EQ(3, q.Quantize(0.3)); + EXPECT_EQ(3, q.Quantize(0.33)); + EXPECT_EQ(3, q.Quantize(1000.0)); +} diff --git a/3rdparty/chromaprint/tests/test_silence_remover.cpp b/3rdparty/chromaprint/tests/test_silence_remover.cpp new file mode 100644 index 000000000..7f067f7fa --- /dev/null +++ b/3rdparty/chromaprint/tests/test_silence_remover.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include +#include "test_utils.h" +#include "silence_remover.h" +#include "audio_buffer.h" +#include "utils.h" + +using namespace std; +using namespace Chromaprint; + +TEST(SilenceRemover, PassThrough) +{ + short samples[] = { 1, 2, 3, 4, 5, 6 }; + vector data(samples, samples + 6); + + boost::scoped_ptr buffer(new AudioBuffer()); + boost::scoped_ptr processor(new SilenceRemover(buffer.get())); + processor->Reset(44100, 1); + processor->Consume(&data[0], data.size()); + processor->Flush(); + + ASSERT_EQ(data.size(), buffer->data().size()); + for (size_t i = 0; i < data.size(); i++) { + ASSERT_EQ(data[i], buffer->data()[i]) << "Signals differ at index " << i; + } +} + +TEST(SilenceRemover, RemoveLeadingSilence) +{ + short samples1[] = { 0, 0, 1, 2, 0, 4, 5, 0 }; + vector data1(samples1, samples1 + 8); + + short samples2[] = { 1, 2, 0, 4, 5, 0 }; + vector data2(samples2, samples2 + 6); + + boost::scoped_ptr buffer(new AudioBuffer()); + boost::scoped_ptr processor(new SilenceRemover(buffer.get())); + processor->Reset(44100, 1); + processor->Consume(&data1[0], data1.size()); + processor->Flush(); + + ASSERT_EQ(data2.size(), buffer->data().size()); + for (size_t i = 0; i < data2.size(); i++) { + ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i; + } +} diff --git a/3rdparty/chromaprint/tests/test_utils.cpp b/3rdparty/chromaprint/tests/test_utils.cpp new file mode 100644 index 000000000..c26e50973 --- /dev/null +++ b/3rdparty/chromaprint/tests/test_utils.cpp @@ -0,0 +1,91 @@ +#include +#include +#include +#include "utils.h" + +using namespace std; +using namespace Chromaprint; + +TEST(Utils, PrepareHammingWindow) { + double window_ex[10] = { 0.08, 0.187619556165, 0.460121838273, 0.77, 0.972258605562, 0.972258605562, 0.77, 0.460121838273, 0.187619556165, 0.08}; + double window[10]; + PrepareHammingWindow(window, window + 10); + for (int i = 0; i < 10; i++) { + EXPECT_FLOAT_EQ(window_ex[i], window[i]); + } +} + +TEST(Utils, ApplyWindow1) { + double window_ex[10] = { 0.08, 0.187619556165, 0.460121838273, 0.77, 0.972258605562, 0.972258605562, 0.77, 0.460121838273, 0.187619556165, 0.08}; + double window[10]; + short input[10]; + double output[10]; + PrepareHammingWindow(window, window + 10); + fill(input, input + 10, numeric_limits::max()); + double scale = 1.0 / numeric_limits::max(); + ApplyWindow(input, window, output, 10, scale); + for (int i = 0; i < 10; i++) { + EXPECT_FLOAT_EQ(window_ex[i], output[i]); + } +} + +TEST(Utils, ApplyWindow2) { + double window[10]; + short input[10]; + double output[10]; + PrepareHammingWindow(window, window + 10); + fill(input, input + 10, 0); + double scale = 1.0 / numeric_limits::max(); + ApplyWindow(input, window, output, 10, scale); + for (int i = 0; i < 10; i++) { + EXPECT_FLOAT_EQ(0.0, output[i]); + } +} + +TEST(Utils, Sum) { + double data[] = { 0.1, 0.2, 0.4, 1.0 }; + EXPECT_FLOAT_EQ(1.7, Sum(data, data + 4)); +} + +TEST(Utils, EuclideanNorm) { + double data[] = { 0.1, 0.2, 0.4, 1.0 }; + EXPECT_FLOAT_EQ(1.1, EuclideanNorm(data, data + 4)); +} + +TEST(Utils, NormalizeVector) { + double data[] = { 0.1, 0.2, 0.4, 1.0 }; + double normalized_data[] = { 0.090909, 0.181818, 0.363636, 0.909091 }; + NormalizeVector(data, data + 4, EuclideanNorm, 0.01); + for (int i = 0; i < 4; i++) { + EXPECT_NEAR(normalized_data[i], data[i], 1e-5) << "Wrong data at index " << i; + } +} + +TEST(Utils, NormalizeVectorNearZero) { + double data[] = { 0.0, 0.001, 0.002, 0.003 }; + NormalizeVector(data, data + 4, EuclideanNorm, 0.01); + for (int i = 0; i < 4; i++) { + EXPECT_FLOAT_EQ(0.0, data[i]) << "Wrong data at index " << i; + } +} + +TEST(Utils, NormalizeVectorZero) { + double data[] = { 0.0, 0.0, 0.0, 0.0 }; + NormalizeVector(data, data + 4, EuclideanNorm, 0.01); + for (int i = 0; i < 4; i++) { + EXPECT_FLOAT_EQ(0.0, data[i]) << "Wrong data at index " << i; + } +} + +TEST(Utils, UnsignedToSigned) { + EXPECT_EQ(numeric_limits::max(), UnsignedToSigned(0x7FFFFFFFU)); + EXPECT_EQ(-1, UnsignedToSigned(0xFFFFFFFFU)); + EXPECT_EQ(-2, UnsignedToSigned(0xFFFFFFFEU)); + EXPECT_EQ(numeric_limits::min(), UnsignedToSigned(0x80000000U)); + EXPECT_EQ(numeric_limits::min() + 1, UnsignedToSigned(0x80000001U)); +} + +TEST(Utils, IsNaN) { + EXPECT_FALSE(IsNaN(0.0)); + EXPECT_TRUE(IsNaN(sqrt(-1.0))); +} diff --git a/3rdparty/chromaprint/tests/test_utils.h b/3rdparty/chromaprint/tests/test_utils.h new file mode 100644 index 000000000..c5898db86 --- /dev/null +++ b/3rdparty/chromaprint/tests/test_utils.h @@ -0,0 +1,42 @@ +#ifndef CHROMAPRINT_TESTS_UTILS_H_ +#define CHROMAPRINT_TESTS_UTILS_H_ + +#include +#include +#include +#ifdef HAVE_CONFIG_H +#include +#endif + +#define NELEMS(x) (sizeof(x)/sizeof(x[0])) + +inline void CheckString(std::string actual, char *expected, int expected_size) +{ + ASSERT_EQ(expected_size, actual.size()); + for (int i = 0; i < expected_size; i++) { + EXPECT_EQ(expected[i], actual[i]) << "Different at index " << i; + } +} + +inline void CheckFingerprints(std::vector actual, int32_t *expected, int expected_size) +{ + ASSERT_EQ(expected_size, actual.size()); + for (int i = 0; i < expected_size; i++) { + EXPECT_EQ(expected[i], actual[i]) << "Different at index " << i; + } +} + +inline std::vector LoadAudioFile(const std::string &file_name) +{ + std::string path = TESTS_DIR + file_name; + std::ifstream file(path.c_str(), std::ifstream::in); + file.seekg(0, std::ios::end); + int length = file.tellg(); + file.seekg(0, std::ios::beg); + std::vector data(length / 2); + file.read((char *)&data[0], length); + file.close(); + return data; +} + +#endif diff --git a/3rdparty/chromaprint/tools/CMakeLists.txt b/3rdparty/chromaprint/tools/CMakeLists.txt new file mode 100644 index 000000000..7c3de7994 --- /dev/null +++ b/3rdparty/chromaprint/tools/CMakeLists.txt @@ -0,0 +1,63 @@ +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/../src + ${FFMPEG_LIBAVCODEC_INCLUDE_DIRS} + ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS} + ${FFMPEG_LIBAVUTIL_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${TAGLIB_INCLUDES} +) + +if(BUILD_EXTRA_TOOLS) + + add_executable(resample resample.cpp) + target_link_libraries(resample chromaprint_p + ${FFMPEG_LIBAVFORMAT_LIBRARIES} + ${FFMPEG_LIBAVCODEC_LIBRARIES} + ${FFMPEG_LIBAVUTIL_LIBRARIES}) + + add_executable(decode decode.cpp) + target_link_libraries(decode chromaprint_p + ${FFMPEG_LIBAVFORMAT_LIBRARIES} + ${FFMPEG_LIBAVCODEC_LIBRARIES} + ${FFMPEG_LIBAVUTIL_LIBRARIES}) + + add_executable(chromagram chromagram.cpp) + target_link_libraries(chromagram chromaprint_p + ${FFMPEG_LIBAVFORMAT_LIBRARIES} + ${FFMPEG_LIBAVCODEC_LIBRARIES} + ${FFMPEG_LIBAVUTIL_LIBRARIES} + -lpng) + + add_executable(spectrogram spectrogram.cpp) + target_link_libraries(spectrogram chromaprint_p + ${FFMPEG_LIBAVFORMAT_LIBRARIES} + ${FFMPEG_LIBAVCODEC_LIBRARIES} + ${FFMPEG_LIBAVUTIL_LIBRARIES} + -lpng) + + add_executable(learn_filters learn_filters.cpp) + target_link_libraries(learn_filters chromaprint_p + ${FFMPEG_LIBAVFORMAT_LIBRARIES} + ${FFMPEG_LIBAVCODEC_LIBRARIES} + ${FFMPEG_LIBAVUTIL_LIBRARIES} + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY}) + + add_executable(fpeval fpeval.cpp) + target_link_libraries(fpeval chromaprint_p + ${FFMPEG_LIBAVFORMAT_LIBRARIES} + ${FFMPEG_LIBAVCODEC_LIBRARIES} + ${FFMPEG_LIBAVUTIL_LIBRARIES} + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY}) + +endif(BUILD_EXTRA_TOOLS) + +if(NOT MSVC) +add_executable(fpcollect fpcollect.cpp) +target_link_libraries(fpcollect chromaprint_p + ${FFMPEG_LIBAVFORMAT_LIBRARIES} + ${FFMPEG_LIBAVCODEC_LIBRARIES} + ${FFMPEG_LIBAVUTIL_LIBRARIES} + ${TAGLIB_LIBRARIES}) +endif() diff --git a/3rdparty/chromaprint/tools/chromagram.cpp b/3rdparty/chromaprint/tools/chromagram.cpp new file mode 100644 index 000000000..17333ff08 --- /dev/null +++ b/3rdparty/chromaprint/tools/chromagram.cpp @@ -0,0 +1,65 @@ +#include +#include + +using namespace std; + +#include "ext/ffmpeg_decoder.h" +#include "ext/audio_dumper.h" +#include "audio_processor.h" +#include "chroma.h" +#include "spectral_centroid.h" +#include "chroma_normalizer.h" +#include "chroma_resampler.h" +#include "chroma_filter.h" +#include "fft.h" +#include "audio_processor.h" +#include "image.h" +#include "image_builder.h" +#include "utils.h" +#include "ext/image_utils.h" + +static const int SAMPLE_RATE = 11025; +static const int FRAME_SIZE = 4096; +static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720; +static const int MIN_FREQ = 28; +static const int MAX_FREQ = 3520; +static const int MAX_FILTER_WIDTH = 20; + +static const int kChromaFilterSize = 5; +static const double kChromaFilterCoefficients[] = { 0.25, 0.75, 1.0, 0.75, 0.25 }; + +int main(int argc, char **argv) +{ + if (argc < 3) { + cerr << "Usage: " << argv[0] << " AUDIOFILE IMAGEFILE\n"; + return 1; + } + + string file_name(argv[1]); + cout << "Loading file " << file_name << "\n"; + + Decoder decoder(file_name); + if (!decoder.Open()) { + cerr << "ERROR: " << decoder.LastError() << "\n"; + return 2; + } + + Chromaprint::Image image(12); + Chromaprint::ImageBuilder image_builder(&image); + Chromaprint::ChromaNormalizer chroma_normalizer(&image_builder); + Chromaprint::ChromaFilter chroma_filter(kChromaFilterCoefficients, kChromaFilterSize, &chroma_normalizer); + //Chromaprint::Chroma chroma(MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &chroma_normalizer); + Chromaprint::Chroma chroma(MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &chroma_filter); + Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, &chroma); + Chromaprint::AudioProcessor processor(SAMPLE_RATE, &fft); + + processor.Reset(decoder.SampleRate(), decoder.Channels()); + decoder.Decode(&processor); + processor.Flush(); + + //Chromaprint::ExportTextImage(&image, argv[2]); + Chromaprint::ExportImage(&image, argv[2]); + + return 0; +} + diff --git a/3rdparty/chromaprint/tools/decode.cpp b/3rdparty/chromaprint/tools/decode.cpp new file mode 100644 index 000000000..a86800469 --- /dev/null +++ b/3rdparty/chromaprint/tools/decode.cpp @@ -0,0 +1,28 @@ +#include +#include + +using namespace std; + +#include "ext/ffmpeg_decoder.h" +#include "ext/audio_dumper.h" + +int main(int argc, char **argv) +{ + if (argc < 3) { + cerr << "Usage: " << argv[0] << " FILENAME\n"; + return 1; + } + + string file_name(argv[1]); + Decoder decoder(file_name); + if (!decoder.Open()) { + cerr << "ERROR: " << decoder.LastError() << "\n"; + return 2; + } + + AudioDumper dumper(argv[2]); + decoder.Decode(&dumper); + + return 0; +} + diff --git a/3rdparty/chromaprint/tools/fillpuid.py b/3rdparty/chromaprint/tools/fillpuid.py new file mode 100755 index 000000000..af37b4a3d --- /dev/null +++ b/3rdparty/chromaprint/tools/fillpuid.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python + +import time +import sys +from optparse import OptionParser +import subprocess +import os.path +from xml.etree import ElementTree + + +usage = "usage: %prog [options] logfile" +parser = OptionParser(usage=usage) +parser.add_option("-a", "--musicdns-apikey", dest="musicdns_api_key", metavar="KEY", + help="MusicDNS API key") +parser.add_option("-g", "--genpuid", dest="genpuid_path", metavar="PATH", + help="path to the GenPUID binary", default="genpuid") + +(options, args) = parser.parse_args() +if len(args) != 1: + parser.error("no log file specified") + + +def read_log_file(input): + group = {} + for line in input: + line = line.strip() + if not line: + if group: + yield group + group = {} + continue + name, value = line.split('=', 1) + group[name] = value + if group: + yield group + + +def make_groups(input, size=10): + group = [] + for entry in input: + group.append(entry) + if len(group) >= size: + yield group + group = [] + if group: + yield group + + + +def write_log_file(entry): + for row in entry.iteritems(): + print '%s=%s' % row + print + + +def call_genpuid(entries): + paths = [e['FILENAME'] for e in entries] + process = subprocess.Popen([options.genpuid_path, options.musicdns_api_key, '-xml'] + paths, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = process.communicate() + tree = ElementTree.fromstring('' + out) + puids = {} + for track in tree.findall("track"): + if 'puid' in track.attrib and 'file' in track.attrib: + puids[os.path.normpath(track.attrib['file']).encode('iso-8859-1')] = track.attrib['puid'] + for entry in entries: + path = os.path.normpath(entry['FILENAME']) + if path in puids: + entry['PUID'] = puids[path] + + +for entries in make_groups(read_log_file(open(args[0]) if args[0] != '-' else sys.stdin), 20): + call_genpuid([e for e in entries if 'MBID' not in e]) + for entry in entries: + print >>sys.stderr, entry['FILENAME'] + write_log_file(entry) + diff --git a/3rdparty/chromaprint/tools/fpcollect.cpp b/3rdparty/chromaprint/tools/fpcollect.cpp new file mode 100644 index 000000000..8ffdb3ec5 --- /dev/null +++ b/3rdparty/chromaprint/tools/fpcollect.cpp @@ -0,0 +1,323 @@ +#include +#include +#include +//#include +#include +#include +#include +#include "chromaprint.h" +#include "fingerprinter.h" +#include "fingerprinter_configuration.h" +#include "fingerprint_compressor.h" +#include "base64.h" +#include "ext/ffmpeg_decoder.h" + +using namespace std; + +static const int kChromaprintAlgorithm = CHROMAPRINT_ALGORITHM_DEFAULT; + +typedef vector string_vector; + +void FindFiles(const string &dirname, string_vector *result, time_t changed_since) +{ + DIR *dirp = opendir(dirname.c_str()); + if (!dirp) { + if (errno == ENOTDIR) { + result->push_back(dirname); + } + return; + } + while (dirp) { + struct dirent *dp; + if ((dp = readdir(dirp)) != NULL) { + struct stat sp; + string filename = dirname + '/' + string(dp->d_name); + stat(filename.c_str(), &sp); + if (S_ISREG(sp.st_mode)) { + //cerr << "file " << filename << " mtime=" << sp.st_mtime << " ch=" << changed_since << "\n"; + if (!changed_since || sp.st_mtime >= changed_since) { + result->push_back(filename); + } + } + if (S_ISDIR(sp.st_mode) && dp->d_name[0] != '.') { + FindFiles(filename, result, changed_since); + } + } + else { + break; + } + } + closedir(dirp); +} + +string_vector FindFiles(const string_vector &files, time_t changed_since) +{ + string_vector result; + for (size_t i = 0; i < files.size(); i++) { + FindFiles(files[i], &result, changed_since); + } + sort(result.begin(), result.end()); + return result; +} + +#define DISPATCH_TAGLIB_FILE(type, file) \ + { \ + type *tmp = dynamic_cast(file); \ + if (tmp) { \ + return ExtractMBIDFromFile(tmp); \ + } \ + } + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef TAGLIB_WITH_ASF +#include +#endif +#ifdef TAGLIB_WITH_MP4 +#include +#endif +#include +#include +#include + +string ExtractMBIDFromXiphComment(TagLib::Ogg::XiphComment *tag) +{ + string key = "MUSICBRAINZ_TRACKID"; + if (tag && tag->fieldListMap().contains(key)) { + return tag->fieldListMap()[key].front().to8Bit(true); + } + return string(); +} + +string ExtractMBIDFromAPETag(TagLib::APE::Tag *tag) +{ + string key = "MUSICBRAINZ_TRACKID"; + if (tag && tag->itemListMap().contains(key)) { + return tag->itemListMap()[key].toString().to8Bit(true); + } + return string(); +} + +string ExtractMBIDFromFile(TagLib::Ogg::Vorbis::File *file) +{ + return ExtractMBIDFromXiphComment(file->tag()); +} + +string ExtractMBIDFromFile(TagLib::Ogg::FLAC::File *file) +{ + return ExtractMBIDFromXiphComment(file->tag()); +} + +string ExtractMBIDFromFile(TagLib::Ogg::Speex::File *file) +{ + return ExtractMBIDFromXiphComment(file->tag()); +} + +string ExtractMBIDFromFile(TagLib::FLAC::File *file) +{ + return ExtractMBIDFromXiphComment(file->xiphComment()); +} + +string ExtractMBIDFromFile(TagLib::MPC::File *file) +{ + return ExtractMBIDFromAPETag(file->APETag()); +} + +string ExtractMBIDFromFile(TagLib::WavPack::File *file) +{ + return ExtractMBIDFromAPETag(file->APETag()); +} + +/*string ExtractMBIDFromFile(TagLib::APE::File *file) +{ + return ExtractMBIDFromAPETag(file->APETag()); +}*/ + +#ifdef TAGLIB_WITH_ASF +string ExtractMBIDFromFile(TagLib::ASF::File *file) +{ + string key = "MusicBrainz/Track Id"; + TagLib::ASF::Tag *tag = file->tag(); + if (tag && tag->attributeListMap().contains(key)) { + return tag->attributeListMap()[key].front().toString().to8Bit(true); + } + return string(); +} +#endif + +#ifdef TAGLIB_WITH_MP4 +string ExtractMBIDFromFile(TagLib::MP4::File *file) +{ + string key = "----:com.apple.iTunes:MusicBrainz Track Id"; + TagLib::MP4::Tag *tag = file->tag(); + if (tag && tag->itemListMap().contains(key)) { + return tag->itemListMap()[key].toStringList().toString().to8Bit(true); + } + return string(); +} +#endif + +string ExtractMBIDFromFile(TagLib::MPEG::File *file) +{ + TagLib::ID3v2::Tag *tag = file->ID3v2Tag(); + if (!tag) { + return string(); + } + TagLib::ID3v2::FrameList ufid = tag->frameListMap()["UFID"]; + if (!ufid.isEmpty()) { + for (TagLib::ID3v2::FrameList::Iterator i = ufid.begin(); i != ufid.end(); i++) { + TagLib::ID3v2::UniqueFileIdentifierFrame *frame = dynamic_cast(*i); + if (frame && frame->owner() == "http://musicbrainz.org") { + TagLib::ByteVector id = frame->identifier(); + return string(id.data(), id.size()); + } + } + } + return string(); +} + +string ExtractMusicBrainzTrackID(TagLib::File *file) +{ + DISPATCH_TAGLIB_FILE(TagLib::FLAC::File, file); + DISPATCH_TAGLIB_FILE(TagLib::Ogg::Vorbis::File, file); + DISPATCH_TAGLIB_FILE(TagLib::Ogg::FLAC::File, file); + DISPATCH_TAGLIB_FILE(TagLib::Ogg::Speex::File, file); + DISPATCH_TAGLIB_FILE(TagLib::MPC::File, file); + DISPATCH_TAGLIB_FILE(TagLib::WavPack::File, file); +#ifdef TAGLIB_WITH_ASF + DISPATCH_TAGLIB_FILE(TagLib::ASF::File, file); +#endif +#ifdef TAGLIB_WITH_MP4 + DISPATCH_TAGLIB_FILE(TagLib::MP4::File, file); +#endif + DISPATCH_TAGLIB_FILE(TagLib::MPEG::File, file); + return string(); +} + +bool ReadTags(const string &filename, bool ignore_missing_mbid) +{ + TagLib::FileRef file(filename.c_str(), true); + if (file.isNull()) + return false; + TagLib::Tag *tags = file.tag(); + TagLib::AudioProperties *props = file.audioProperties(); + if (!tags || !props) + return false; + //cout << "ARTIST=" << tags->artist().to8Bit(true) << "\n"; + //cout << "TITLE=" << tags->title().to8Bit(true) << "\n"; + //cout << "ALBUM=" << tags->album().to8Bit(true) << "\n"; + int length = props->length(); + if (!length) + return false; + string mbid = ExtractMusicBrainzTrackID(file.file()); + if (mbid.size() != 36 && !ignore_missing_mbid) + return false; + if (mbid.size() == 36) + cout << "MBID=" << mbid << "\n"; + cout << "LENGTH=" << length << "\n"; + cout << "BITRATE=" << props->bitrate() << "\n"; + return true; +} + +string ExtractExtension(const string &filename) +{ + size_t pos = filename.find_last_of('.'); + if (pos == string::npos) { + return string(); + } + return boost::to_upper_copy(filename.substr(pos + 1)); +} + +string EncodeFingerprint(const vector &fp) +{ + string res; + res.resize(fp.size()); + return res; +} + +bool ProcessFile(Chromaprint::Fingerprinter *fingerprinter, const string &filename, bool ignore_missing_mbid, int audio_length) +{ + if (!ReadTags(filename, ignore_missing_mbid)) + return false; + Decoder decoder(filename); + if (!decoder.Open()) + return false; + if (!fingerprinter->Start(decoder.SampleRate(), decoder.Channels())) + return false; + cerr << filename << "\n"; + cout << "FILENAME=" << filename << "\n"; + cout << "FORMAT=" << ExtractExtension(filename) << "\n"; + decoder.Decode(fingerprinter, audio_length); + vector fp = fingerprinter->Finish(); + /*cout << "FINGERPRINT1="; + for (int i = 0; i < fp.size(); i++) { + cout << fp[i] << ", "; + } + cout << "\n";*/ + cout << "FINGERPRINT=" << Chromaprint::Base64Encode(Chromaprint::CompressFingerprint(fp, kChromaprintAlgorithm)) << "\n\n"; + return true; +} + +int main(int argc, char **argv) +{ + if (argc < 2) { + cerr << "Usage: " << argv[0] << " [OPTIONS] FILE...\n"; + cerr << "Options:\n"; + cerr << " -nombid Do not require a MBID embedded in the file\n"; + cerr << " -since DATE Process only files modified since the given date\n"; + cerr << " -length SECONDS Length of the audio data used for fingerprinting (default 120)\n"; + return 1; + } + + string_vector files; + char *changed_since_str = NULL; + int audio_length = 120; + bool ignore_missing_mbid = false; + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-nombid") == 0) { + ignore_missing_mbid = true; + } + else if (strcmp(argv[i], "-since") == 0 && i + 1 < argc) { + changed_since_str = argv[++i]; + } + else if (strcmp(argv[i], "-length") == 0 && i + 1 < argc) { + audio_length = atoi(argv[++i]); + } + else { + files.push_back(argv[i]); + } + } + + time_t changed_since = 0; + if (changed_since_str) { + struct tm tm; + memset(&tm, 0, sizeof(tm)); + if (strptime(changed_since_str, "%Y-%m-%d %H:%M", &tm) == NULL) { + if (strptime(changed_since_str, "%Y-%m-%d", &tm) == NULL) { + cerr << "ERROR: Invalid date, the expected format is 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM'\n"; + return 1; + } + } + tm.tm_isdst = -1; + changed_since = mktime(&tm); + //cerr << "Calculating fingerprints for files in " << files << " that were changed since " << changed_since_str << "\n"; + } + else { + //cerr << "Calculating fingerprints for all files in " << files << "\n"; + } + + Chromaprint::Fingerprinter fingerprinter(Chromaprint::CreateFingerprinterConfiguration(kChromaprintAlgorithm)); + files = FindFiles(files, changed_since); + for (string_vector::iterator it = files.begin(); it != files.end(); it++) { + ProcessFile(&fingerprinter, *it, ignore_missing_mbid, audio_length); + } + + return 0; +} + diff --git a/3rdparty/chromaprint/tools/fpeval.cpp b/3rdparty/chromaprint/tools/fpeval.cpp new file mode 100644 index 000000000..b003c7a2f --- /dev/null +++ b/3rdparty/chromaprint/tools/fpeval.cpp @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "ext/ffmpeg_decoder.h" +#include "ext/image_utils.h" +#include "audio_processor.h" +#include "fingerprinter.h" +#include "image.h" +#include "integral_image.h" +#include "image_builder.h" +#include "utils.h" +#include "filter.h" +#include "lloyds.h" +#include "classifier.h" +#include "match.h" + +using namespace std; +using namespace Chromaprint; +namespace fs = boost::filesystem; + +typedef vector string_vector; +typedef vector double_vector; + +string_vector FindAudioFiles(const char *dirname) +{ + string_vector result; + fs::path path(dirname); + fs::directory_iterator end_iter; + for (fs::directory_iterator dir_iter(path); dir_iter != end_iter; ++dir_iter) { + if (fs::is_regular_file(dir_iter->status())) { + string filename = dir_iter->path().string(); + if (boost::ends_with(filename, ".mp3") || boost::ends_with(filename, ".wav")) { + result.push_back(filename); + } + } + } + sort(result.begin(), result.end()); + return result; +} + +vector GenerateFilePairs(const vector &files) +{ + string last_name; + vector result; + for (int i = 0; i < files.size(); i++) { + string name = fs::basename(files[i]); + name = name.substr(0, name.find_first_of('-')); + if (last_name != name) { + result.push_back(string_vector()); + last_name = name; + } + result.back().push_back(files[i]); + } + return result; +} + +vector MultiMapValues(const multimap &data, const int &key) +{ + pair::const_iterator, multimap::const_iterator> range = data.equal_range(key); + vector result; + for (multimap::const_iterator i = range.first; i != range.second; ++i) { + result.push_back((*i).second); + } + return result; +} + +static const int SAMPLE_RATE = 11025; +static const int FRAME_SIZE = 4096; +static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720; +static const int MIN_FREQ = 28; +static const int MAX_FREQ = 3520; +static const int MAX_FILTER_WIDTH = 16; +/*static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 2;// 2720; +static const int MIN_FREQ = 300; +static const int MAX_FREQ = 5300; +static const int MAX_FILTER_WIDTH = 20;*/ + +void PrintRate(const std::string &name, const std::vector &values, int scale) +{ + cout << name << " = ["; + for (int j = 0; j < 32; j++) { + double rate = double(values[j]) / scale; + if (j != 0) std::cout << ", "; + std::cout << rate; + } + cout << "]\n"; +} + +#define FP_TYPE_CHROMA 1 +#define FP_TYPE_CENTROID 2 +#define FP_TYPE FP_TYPE_CHROMA + +int main(int argc, char **argv) +{ + Chromaprint::Fingerprinter fingerprinter; + + vector files = FindAudioFiles(argv[1]); + vector< string > names[2]; + vector< vector > fingerprints[2]; + for (int i = 0; i < files.size(); i++) { + cout << " - " << files[i] << "\n"; + Decoder decoder(files[i]); + if (!decoder.Open()) { + cerr << "ERROR: " << decoder.LastError() << "\n"; + return 1; + } + fingerprinter.Start(decoder.SampleRate(), decoder.Channels()); + decoder.Decode(&fingerprinter, 60); + vector fp = fingerprinter.Finish(); + int orig = files[i].find("orig") != string::npos ? 1 : 0; + fingerprints[orig].push_back(fp); + names[orig].push_back(files[i]); + } + int num_files = files.size() / 2; + + typedef boost::multi_array DoubleArray2D; + + float total = 0.0f, diagonal = 0.0f; + DoubleArray2D confmatrix(boost::extents[num_files][num_files]); + for (int i = 0; i < num_files; i++) { + for (int j = 0; j < num_files; j++) { + float score = match_fingerprints(fingerprints[0][i], fingerprints[1][j]); + cout << " - " << names[0][i] << " / " << names[1][j] << " = " << score <<"\n"; + confmatrix[i][j] = score; + if (i == j) { + diagonal += score; + } + total += score; + } + } + + cout << "true positive: " << diagonal / num_files << "\n"; + cout << "false positive: " << (total - diagonal) / (num_files * num_files - num_files) << "\n"; + cout << "score: " << diagonal / total << "\n"; + return 0; +} + diff --git a/3rdparty/chromaprint/tools/fpsubmit.py b/3rdparty/chromaprint/tools/fpsubmit.py new file mode 100755 index 000000000..9bc2fb722 --- /dev/null +++ b/3rdparty/chromaprint/tools/fpsubmit.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python + +import time +import sys +import urllib2 +import urllib +import gzip +import socket +from cStringIO import StringIO +from optparse import OptionParser + + +usage = "usage: %prog [options] logfile" +parser = OptionParser(usage=usage) +parser.add_option("-a", "--api-key", dest="api_key", metavar="KEY", + help="your Acoustid API key (http://acoustid.org/api-key)") +parser.add_option("-b", "--batch-size", dest="batch_size", type="int", + default=50, metavar="SIZE", + help="how many fingerprints to submit in one request [default: %default]") +parser.add_option("--app-url", dest="app_url", type="string", + default='http://api.acoustid.org/submit', + help="how many fingerprints to submit in one request [default: %default]") +parser.add_option("--app-api-key", dest="app_api_key", type="string", default='5hOby2eZ', + help="application API key (needed only if you submit to a non-default URL)") +parser.add_option("-s", "--start", dest="start", type="int", + default=1, metavar="SIZE", + help="start with the Nth entry from the log file [default: %default]") + +(options, args) = parser.parse_args() +if not options.api_key: + parser.error("no API key specified") +if len(args) != 1: + parser.error("no log file specified") + + +USER_API_KEY = options.api_key +CLIENT_API_KEY = options.app_api_key +API_URL = options.app_url +BATCH_SIZE = options.batch_size + + +def read_log_file(input): + group = {} + for line in input: + line = line.strip() + if not line: + if group: + yield group + group = {} + continue + name, value = line.split('=', 1) + group[name] = value + if group: + yield group + + +def encode_params(data): + encoded_body = StringIO() + encoded_file = gzip.GzipFile(mode='w', fileobj=encoded_body) + encoded_file.write(urllib.urlencode(data)) + encoded_file.close() + return encoded_body.getvalue() + + +def submit_data(i, entries): + if not entries: + return True + params = { 'user': USER_API_KEY, 'client': CLIENT_API_KEY } + print 'Submitting... (entries from %d to %d)' % (i, i + len(entries) - 1) + i = 0 + for entry in [e for e in entries if e['LENGTH'] >= 40 and len(e['FINGERPRINT'])>100]: + if 'MBID' not in entry and 'PUID' not in entry or int(entry.get('LENGTH', '0')) <= 0: + continue + if 'MBID' in entry: + print ' MBID ', entry['MBID'], entry['FINGERPRINT'][:20] + '...' + for mbid in entry['MBID'].split(','): + params['mbid.%d' % i] = mbid + if 'PUID' in entry: + print ' PUID ', entry['PUID'], entry['FINGERPRINT'][:20] + '...' + params['puid.%d' % i] = entry['PUID'] + params['fingerprint.%d' % i] = entry['FINGERPRINT'] + params['length.%d' % i] = entry['LENGTH'] + if 'BITRATE' in entry: + params['bitrate.%d' % i] = entry['BITRATE'] + if 'FORMAT' in entry: + params['format.%d' % i] = entry['FORMAT'] + i += 1 + data = encode_params(params) + request = urllib2.Request(API_URL, data, headers={'Content-Encoding': 'gzip'}) + try: + urllib2.urlopen(request) + except urllib2.HTTPError, e: + print e + for line in e.readlines(): + print line.rstrip() + return False + except urllib2.URLError, e: + print e + return False + except socket.error, e: + print e + return False + print 'OK' + return True + + +batch = [] +i = options.start +j = 0 +for entry in read_log_file(open(args[0]) if args[0] != '-' else sys.stdin): + j += 1 + if j < options.start: + continue + batch.append(entry) + if len(batch) >= BATCH_SIZE: + submit_data(i, batch) + i = j + batch = [] + time.sleep(0.1) +submit_data(i, batch) + diff --git a/3rdparty/chromaprint/tools/learn_filters.cpp b/3rdparty/chromaprint/tools/learn_filters.cpp new file mode 100644 index 000000000..01663abae --- /dev/null +++ b/3rdparty/chromaprint/tools/learn_filters.cpp @@ -0,0 +1,396 @@ +#include +#include +#include +#include +#include +#include +#include +#include "ext/ffmpeg_decoder.h" +#include "ext/image_utils.h" +#include "audio_processor.h" +#include "chroma.h" +#include "spectral_centroid.h" +#include "chroma_normalizer.h" +#include "chroma_resampler.h" +#include "chroma_filter.h" +#include "fft.h" +#include "audio_processor.h" +#include "image.h" +#include "integral_image.h" +#include "image_builder.h" +#include "utils.h" +#include "filter.h" +#include "lloyds.h" +#include "classifier.h" + +using namespace std; +using namespace Chromaprint; +namespace fs = boost::filesystem; + +typedef vector string_vector; +typedef vector double_vector; + +string_vector FindAudioFiles(const char *dirname) +{ + string_vector result; + fs::path path(dirname); + fs::directory_iterator end_iter; + for (fs::directory_iterator dir_iter(path); dir_iter != end_iter; ++dir_iter) { + if (fs::is_regular_file(dir_iter->status())) { + string filename = dir_iter->path().string(); + if (boost::ends_with(filename, ".mp3") || boost::ends_with(filename, ".wma") || boost::ends_with(filename, ".wav")) { + result.push_back(filename); + } + } + } + sort(result.begin(), result.end()); + return result; +} + +vector GenerateFilePairs(const vector &files) +{ + string last_name; + vector result; + for (int i = 0; i < files.size(); i++) { + string name = fs::basename(files[i]); + name = name.substr(0, name.find_first_of('-')); + if (last_name != name) { + result.push_back(string_vector()); + last_name = name; + } + result.back().push_back(files[i]); + } + return result; +} + +vector MultiMapValues(const multimap &data, const int &key) +{ + pair::const_iterator, multimap::const_iterator> range = data.equal_range(key); + vector result; + for (multimap::const_iterator i = range.first; i != range.second; ++i) { + result.push_back((*i).second); + } + return result; +} + +static const int SAMPLE_RATE = 11025; +static const int FRAME_SIZE = 4096; +static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720; +static const int MIN_FREQ = 28; +static const int MAX_FREQ = 3520; +static const int MAX_FILTER_WIDTH = 16; +/*static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 2;// 2720; +static const int MIN_FREQ = 300; +static const int MAX_FREQ = 5300; +static const int MAX_FILTER_WIDTH = 20;*/ + +static const int TRAINING_SET_SIZE = 60000; + +void PrintRate(const std::string &name, const std::vector &values, int scale) +{ + cout << name << " = ["; + for (int j = 0; j < 32; j++) { + double rate = double(values[j]) / scale; + if (j != 0) std::cout << ", "; + std::cout << rate; + } + cout << "]\n"; +} + +#define FP_TYPE_CHROMA 1 +#define FP_TYPE_CENTROID 2 +#define FP_TYPE FP_TYPE_CHROMA + +int main(int argc, char **argv) +{ + Chromaprint::ImageBuilder image_builder; +#if FP_TYPE == FP_TYPE_CHROMA + Chromaprint::ChromaNormalizer chroma_normalizer(&image_builder); + static const double kChromaFilterCoeffs[] = { 0.25, 0.75, 1.0, 0.75, 0.25 }; + Chromaprint::ChromaFilter chroma_filter(kChromaFilterCoeffs, 5, &chroma_normalizer); + Chromaprint::Chroma chroma(MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &chroma_filter); + //chroma.set_interpolate(true); + Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, &chroma); +#elif FP_TYPE == FP_TYPE_CHROMA + Chromaprint::SpectralCentroid centroid(16, MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &image_builder); + Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, ¢roid); +#endif + Chromaprint::AudioProcessor processor(SAMPLE_RATE, &fft); + + cout << "Loading audio files\n"; + vector files = GenerateFilePairs(FindAudioFiles(argv[1])); + vector groups; + multimap reverse_groups; + vector images; + vector integral_images; + for (int i = 0; i < files.size(); i++) { + //cout << i << ".\n"; + for (int j = 0; j < files[i].size(); j++) { + cout << " - " << files[i][j] << "\n"; + Decoder decoder(files[i][j]); + if (!decoder.Open()) { + cerr << "ERROR: " << decoder.LastError() << "\n"; + return 1; + } +#if FP_TYPE == FP_TYPE_CHROMA + Image *image = new Image(12); +#elif FP_TYPE == FP_TYPE_CENTROID + Image *image = new Image(16); +#endif + processor.Reset(decoder.SampleRate(), decoder.Channels()); + fft.Reset(); +#if FP_TYPE == FP_TYPE_CHROMA + chroma.Reset(); + chroma_filter.Reset(); + chroma_normalizer.Reset(); +#elif FP_TYPE == FP_TYPE_CENTROID + centroid.Reset(); +#endif + image_builder.Reset(image); + decoder.Decode(&processor); + processor.Flush(); + //ExportTextImage(image, files[i][j] + ".img.txt"); + //Chromaprint::ExportImage(image_builder.image(), files[i][j] + ".img.png"); + reverse_groups.insert(make_pair(i, images.size())); + groups.push_back(i); + images.push_back(image); + IntegralImage *int_image = new IntegralImage(image) ; + // ExportTextImage(int_image, files[i][j] + ".int_img.txt"); + integral_images.push_back(int_image); + //ExportTextImage(int_image, files[i][j] + ".img.txt"); + // return 1; + } + cout << images.size() << "\r"; + cout.flush(); + } + + cout << "Training data set:\n"; + cout << " - File groups: " << files.size() << "\n"; + cout << " - Files: " << images.size() << "\n"; + files.clear(); + + bool labels[TRAINING_SET_SIZE]; + int data1[TRAINING_SET_SIZE]; + int data2[TRAINING_SET_SIZE]; + int data1_pos[TRAINING_SET_SIZE]; + int data2_pos[TRAINING_SET_SIZE]; + + int i = 0; + srand(3); + // Find matching pairs + for (; i < TRAINING_SET_SIZE / 2; i++) { + int x1 = rand() % images.size(); + vector group = MultiMapValues(reverse_groups, groups[x1]); + int x2; + do { + x2 = group[rand() % group.size()]; + } while (x1 == x2); + size_t min_length = min(images[x1]->NumRows(), images[x2]->NumRows()); + int pos = rand() % (min_length - 30); + //cout << "+ " << x1 << " " << x2 << " - " << pos << "\n"; + data1[i] = x1; + data2[i] = x2; + data1_pos[i] = pos; + data2_pos[i] = pos; + labels[i] = true; + } + // Find non-matching pairs + for (; i < TRAINING_SET_SIZE; i++) { + int x2, x1 = rand() % images.size(); + int pos2, pos1 = rand() % (images[x1]->NumRows() - 30); + vector group = MultiMapValues(reverse_groups, groups[x1]); + set group_set(group.begin(), group.end()); + do { + x2 = rand() % images.size(); + pos2 = rand() % (images[x2]->NumRows() - 30); + } while (group_set.count(x2) && abs(pos1 - pos2) < 50); + //cout << "- " << x1 << " " << x2 << " - " << pos1 << " " << pos2 << "\n"; + data1[i] = x1; + data2[i] = x2; + data1_pos[i] = pos1; + data2_pos[i] = pos2; + labels[i] = false; + } + + const float maxWidth = 16.0; + const float widthScale = 1.0; + const float widthIncrement = 1.0; + + const int numFilters = 6; + const int maxHeight = images[0]->NumColumns(); + const int filterWidthInc[] = { 1, 1, 2, 2, 1, 3 }; + const int filterHeightInc[] = { 1, 2, 1, 2, 3, 1 }; + const int kNumCandidateQuantizers = 24; + + double weights[TRAINING_SET_SIZE]; + for (int i = 0; i < TRAINING_SET_SIZE; i++) { + weights[i] = 1.0 / TRAINING_SET_SIZE; + } + + cout << "Computing filter responses\n"; + std::vector filters; + double *values_buffer = new double[100 * TRAINING_SET_SIZE * 2]; + + Filter flt; + FILE *f = fopen("filters.tmp", "wb"); + for (int filter = 0; filter < numFilters; filter++) { + flt.set_type(filter); + for (int y = 0; y < maxHeight; y++) { + flt.set_y(y); + for (int h = filterHeightInc[filter]; h < maxHeight - y; h += filterHeightInc[filter]) { + flt.set_height(h); + int pw = 0; + for (int wf = filterWidthInc[filter]; wf <= maxWidth; wf += filterWidthInc[filter]) { + int w = wf; + if (pw == w) + continue; + flt.set_width(w); + fill(values_buffer, values_buffer + TRAINING_SET_SIZE * 2, 0.0); + for (int i = 0; i < TRAINING_SET_SIZE; i++) { + double value1 = flt.Apply(integral_images[data1[i]], data1_pos[i]); + double value2 = flt.Apply(integral_images[data2[i]], data2_pos[i]); + //cout << flt << " " << value1 << " [" << data1[i] << ":" << data1_pos[i] << "] " << value2 << " [" << data2[i] << ":" << data2_pos[i] << "]\n"; + values_buffer[2*i+0] = value1; + values_buffer[2*i+1] = value2; + } + fwrite(values_buffer, sizeof(double), TRAINING_SET_SIZE * 2, f); + filters.push_back(flt); + } + } + } + } + cout << "Filters: " << filters.size() << "\n"; + + fclose(f); + f = fopen("filters.tmp", "rb"); + + cout << "Computing quantizers\n"; + double *all_candidate_quantizers = new double[filters.size() * kNumCandidateQuantizers]; + double *quantizer_ptr = all_candidate_quantizers; + fseek(f, 0, SEEK_SET); + double *values_ptr = values_buffer + 100 * TRAINING_SET_SIZE * 2; + for (int filter_i = 0; filter_i < filters.size(); filter_i++) { + int num_values = TRAINING_SET_SIZE * 2; + if (values_ptr >= values_buffer + 100 * TRAINING_SET_SIZE * 2) { + fread(values_buffer, sizeof(double), 100 * num_values, f); + values_ptr = values_buffer; + } + double_vector candidate_quantizers = lloyds(values_ptr, values_ptr + num_values, kNumCandidateQuantizers); + copy(candidate_quantizers.begin(), candidate_quantizers.end(), quantizer_ptr); + quantizer_ptr += kNumCandidateQuantizers; + values_ptr += num_values; + cout << filter_i << "\r"; + cout.flush(); + } + + cout << "Running AdaBoost\n"; + vector best_classifiers; + vector best_classifiers_alpha; + + int iteration = 0; +next_iteration: + + double min_error = 1.0; + Classifier best_classifier; + boost::dynamic_bitset<> best_results(TRAINING_SET_SIZE); + fseek(f, 0, SEEK_SET); + quantizer_ptr = all_candidate_quantizers; + values_ptr = values_buffer + 100 * TRAINING_SET_SIZE * 2; + for (int filter_i = 0; filter_i < filters.size(); filter_i++) { + std::size_t num_values = TRAINING_SET_SIZE * 2; + if (values_ptr >= values_buffer + 100 * TRAINING_SET_SIZE * 2) { + fread(values_buffer, sizeof(double), 100 * num_values, f); + values_ptr = values_buffer; + } + + Quantizer quantizer(0.0, 0.0, 0.0); + for (int ti0 = 0; ti0 < kNumCandidateQuantizers - 3; ti0++) { + quantizer.set_t0(quantizer_ptr[ti0]); + for (int ti1 = ti0 + 1; ti1 < kNumCandidateQuantizers - 2; ti1++) { + quantizer.set_t1(quantizer_ptr[ti1]); + for (int ti2 = ti1 + 1; ti2 < kNumCandidateQuantizers - 1; ti2++) { + quantizer.set_t2(quantizer_ptr[ti2]); + double error = 0.0; + for (int i = 0; i < TRAINING_SET_SIZE; i++) { + int q1 = quantizer.Quantize(values_ptr[i*2 + 0]); + int q2 = quantizer.Quantize(values_ptr[i*2 + 1]); + bool match = (q1 == q2) == labels[i]; + if (!match) { + error += weights[i]; + } + } + if (error < min_error) { + best_classifier = Classifier(filters[filter_i], quantizer); + min_error = error; + for (int i = 0; i < TRAINING_SET_SIZE; i++) { + int q1 = quantizer.Quantize(values_ptr[i*2 + 0]); + int q2 = quantizer.Quantize(values_ptr[i*2 + 1]); + bool match = (q1 == q2) == labels[i]; + best_results[i] = match; + } + } + } + } + } + quantizer_ptr += kNumCandidateQuantizers; + values_ptr += num_values; + cout << filter_i << " [" << min_error << "] \r"; + cout.flush(); + } + + double weight_sum = 0.0; + double alpha = 0.5 * log((1.0 - min_error) / min_error); + for (int i = 0; i < TRAINING_SET_SIZE; i++) { + weights[i] *= exp(-alpha * (best_results[i] ? 1.0 : -1.0)); + weight_sum += weights[i]; + } + for (int i = 0; i < TRAINING_SET_SIZE; i++) { + weights[i] /= weight_sum; + } + + best_classifiers.push_back(best_classifier); + best_classifiers_alpha.push_back(alpha); + + int wrong = 0; + int counts[2]; + counts[0] = 0; + counts[1] = 0; + std::vector bit_tp(32, 0); + std::vector bit_fp(32, 0); + for (int i = 0; i < TRAINING_SET_SIZE; i++) { + double value = 0.0; + int bit_error = 0; + for (int j = 0; j < best_classifiers.size(); j++) { + int q1 = best_classifiers[j].Classify(integral_images[data1[i]], data1_pos[i]); + int q2 = best_classifiers[j].Classify(integral_images[data2[i]], data2_pos[i]); + int e = abs(q1 - q2); + bit_error += e == 3 ? 1 : e; + value += best_classifiers_alpha[j] * (q1 == q2 ? 1.0 : -1.0); + } + bool match = value > 0.0; + counts[labels[i]]++; + if (labels[i] != match) { + wrong += 1.0; + } + for (int j = 0; j < 32; j++) { + bool bit_match = bit_error <= j; + if (labels[i] && bit_match) { + bit_tp[j]++; + } + if (!labels[i] && bit_match) { + bit_fp[j]++; + } + } + } + + ++iteration; + cout << iteration << ". best classifier is " << best_classifier << " with error " << min_error << " (alpha " << alpha << "), final error is " << double(wrong) / TRAINING_SET_SIZE << "\n"; + PrintRate("TP", bit_tp, counts[1]); + PrintRate("FP", bit_fp, counts[0]); + + if (iteration < 16) + goto next_iteration; + + return 0; +} + diff --git a/3rdparty/chromaprint/tools/match.h b/3rdparty/chromaprint/tools/match.h new file mode 100644 index 000000000..aabe61673 --- /dev/null +++ b/3rdparty/chromaprint/tools/match.h @@ -0,0 +1,42 @@ +#include +#include +#include + +/* fingerprint matcher settings */ +#define ACOUSTID_MAX_BIT_ERROR 2 +#define ACOUSTID_MAX_ALIGN_OFFSET 120 + +#define BITCOUNT(x) __builtin_popcount(x) + +inline float +match_fingerprints(const std::vector &a, const std::vector &b) +{ + int i, j, topcount; + int maxsize = std::max(a.size(), b.size()); + int numcounts = maxsize * 2 + 1; + int *counts = (int*)malloc(sizeof(int) * numcounts); + + memset(counts, 0, sizeof(int) * numcounts); + for (i = 0; i < a.size(); i++) { + int jbegin = std::max(0, i - ACOUSTID_MAX_ALIGN_OFFSET); + int jend = std::min(b.size(), size_t(i + ACOUSTID_MAX_ALIGN_OFFSET)); + for (j = jbegin; j < jend; j++) { + int biterror = BITCOUNT(a[i] ^ b[j]); + if (biterror <= ACOUSTID_MAX_BIT_ERROR) { + int offset = i - j + maxsize; + counts[offset]++; + } + } + } + + topcount = 0; + for (i = 0; i < numcounts; i++) { + if (counts[i] > topcount) { + topcount = counts[i]; + } + } + + free(counts); + + return (float)topcount / std::min(a.size(), b.size()); +} diff --git a/3rdparty/chromaprint/tools/misc/prepare-128mp3.sh b/3rdparty/chromaprint/tools/misc/prepare-128mp3.sh new file mode 100755 index 000000000..b3b0c3573 --- /dev/null +++ b/3rdparty/chromaprint/tools/misc/prepare-128mp3.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +for FILE in `ls *-orig.wav`; do + TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-128mp3.mp3/'` + NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-128mp3.wav/'` + if [ ! -f $NEWFILE ]; then + rm -f $NEWFILE + ffmpeg -i $FILE -ab 128000 $TMPNEWFILE + ffmpeg -i $TMPNEWFILE $NEWFILE + rm -f $TMPNEWFILE + fi +done + diff --git a/3rdparty/chromaprint/tools/misc/prepare-32mp3.sh b/3rdparty/chromaprint/tools/misc/prepare-32mp3.sh new file mode 100755 index 000000000..18a7ab24e --- /dev/null +++ b/3rdparty/chromaprint/tools/misc/prepare-32mp3.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +for FILE in `ls *-orig.wav`; do + TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-32mp3.mp3/'` + NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-32mp3.wav/'` + if [ ! -f $NEWFILE ]; then + rm -f $NEWFILE + ffmpeg -i $FILE -ab 32000 $TMPNEWFILE + ffmpeg -i $TMPNEWFILE $NEWFILE + rm -f $TMPNEWFILE + fi +done + diff --git a/3rdparty/chromaprint/tools/misc/prepare-64mp3.sh b/3rdparty/chromaprint/tools/misc/prepare-64mp3.sh new file mode 100755 index 000000000..23f1a86ce --- /dev/null +++ b/3rdparty/chromaprint/tools/misc/prepare-64mp3.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +for FILE in `ls *-orig.wav`; do + TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-64mp3.mp3/'` + NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-64mp3.wav/'` + if [ ! -f $NEWFILE ]; then + rm -f $NEWFILE + ffmpeg -i $FILE -ab 64000 $TMPNEWFILE + ffmpeg -i $TMPNEWFILE $NEWFILE + rm -f $TMPNEWFILE + fi +done + diff --git a/3rdparty/chromaprint/tools/misc/prepare-64wma.sh b/3rdparty/chromaprint/tools/misc/prepare-64wma.sh new file mode 100755 index 000000000..f99d5f441 --- /dev/null +++ b/3rdparty/chromaprint/tools/misc/prepare-64wma.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +for FILE in `ls *-orig.wav`; do + TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-64wma.wma/'` + NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-64wma.wav/'` + if [ ! -f $NEWFILE ]; then + rm -f $NEWFILE + ffmpeg -i $FILE -ab 64000 -acodec wmav2 $TMPNEWFILE + ffmpeg -i $TMPNEWFILE $NEWFILE + rm -f $TMPNEWFILE + fi +done + diff --git a/3rdparty/chromaprint/tools/misc/prepare-gain.sh b/3rdparty/chromaprint/tools/misc/prepare-gain.sh new file mode 100755 index 000000000..7bae2c07c --- /dev/null +++ b/3rdparty/chromaprint/tools/misc/prepare-gain.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +for FILE in `ls *-orig.wav`; do + TMP1FILE=`echo $FILE | perl -pe 's/-orig\..*$/-tmp.wav/'` + TMP2FILE=`echo $FILE | perl -pe 's/-orig\..*$/-tmp2.wav/'` + TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-gain.wma/'` + NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-gain.wav/'` + if [ ! -f $NEWFILE ]; then + rm -f $NEWFILE $TMP1FILE $TMP2FILE + ffmpeg -i $FILE $TMP1FILE + sox $TMP1FILE $TMP2FILE gain -n -10 + ffmpeg -i $TMP2FILE -ab 128000 -acodec wmav2 $TMPNEWFILE + ffmpeg -i $TMPNEWFILE $NEWFILE + rm -f $TMP1FILE $TMP2FILE $TMPNEWFILE + fi +done + diff --git a/3rdparty/chromaprint/tools/misc/prepare-resample.sh b/3rdparty/chromaprint/tools/misc/prepare-resample.sh new file mode 100755 index 000000000..0bb01b854 --- /dev/null +++ b/3rdparty/chromaprint/tools/misc/prepare-resample.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +for FILE in `ls *-orig.wav`; do + TMP1FILE=`echo $FILE | perl -pe 's/-orig\..*$/-tmp.wav/'` + TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-resample.wma/'` + NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-resample.wav/'` + if [ ! -f $NEWFILE ]; then + rm -f $NEWFILE $TMP1FILE $TMPNEWFILE + sox $FILE $TMP1FILE rate -l 8k + ffmpeg -i $TMP1FILE -ab 128000 -acodec wmav2 $TMPNEWFILE + ffmpeg -i $TMPNEWFILE $NEWFILE + rm -f $TMP1FILE $TMPNEWFILE + fi +done + diff --git a/3rdparty/chromaprint/tools/misc/prepare-wav.sh b/3rdparty/chromaprint/tools/misc/prepare-wav.sh new file mode 100755 index 000000000..d0d7c0884 --- /dev/null +++ b/3rdparty/chromaprint/tools/misc/prepare-wav.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +for FILE in `ls *.{mp3,wma,ogg}`; do + NEWFILE=`echo $FILE | perl -pe 's/\..*$/.wav/'` + rm -f $NEWFILE + ffmpeg -i $FILE $NEWFILE + rm -f $FILE +done + diff --git a/3rdparty/chromaprint/tools/misc/prepare.sh b/3rdparty/chromaprint/tools/misc/prepare.sh new file mode 100755 index 000000000..869f1b81d --- /dev/null +++ b/3rdparty/chromaprint/tools/misc/prepare.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +cp orig/*.wav . +./prepare-32mp3.sh +./prepare-64mp3.sh +./prepare-128mp3.sh +./prepare-64wma.sh +./prepare-gain.sh +./prepare-wav.sh diff --git a/3rdparty/chromaprint/tools/resample.cpp b/3rdparty/chromaprint/tools/resample.cpp new file mode 100644 index 000000000..77a18f364 --- /dev/null +++ b/3rdparty/chromaprint/tools/resample.cpp @@ -0,0 +1,35 @@ +#include +#include + +using namespace std; + +#include "ext/ffmpeg_decoder.h" +#include "ext/audio_dumper.h" +#include "audio_processor.h" + +int main(int argc, char **argv) +{ + if (argc < 2) { + cerr << "Usage: " << argv[0] << " FILENAME\n"; + return 1; + } + + string file_name(argv[1]); + cout << "Loading file " << file_name << "\n"; + + Decoder decoder(file_name); + if (!decoder.Open()) { + cerr << "ERROR: " << decoder.LastError() << "\n"; + return 2; + } + + AudioDumper dumper("resampled.raw"); + Chromaprint::AudioProcessor processor(11025, &dumper); + processor.Reset(decoder.SampleRate(), decoder.Channels()); + + decoder.Decode(&processor); + processor.Flush(); + + return 0; +} + diff --git a/3rdparty/chromaprint/tools/spectrogram.cpp b/3rdparty/chromaprint/tools/spectrogram.cpp new file mode 100644 index 000000000..8fe4a5793 --- /dev/null +++ b/3rdparty/chromaprint/tools/spectrogram.cpp @@ -0,0 +1,63 @@ +#include +#include + +using namespace std; + +#include "ext/ffmpeg_decoder.h" +#include "ext/audio_dumper.h" +#include "audio_processor.h" +#include "chroma.h" +#include "spectrum.h" +#include "chroma_normalizer.h" +#include "chroma_resampler.h" +#include "chroma_filter.h" +#include "fft.h" +#include "audio_processor.h" +#include "image.h" +#include "image_builder.h" +#include "utils.h" +#include "ext/image_utils.h" + +static const int SAMPLE_RATE = 11025; +static const int FRAME_SIZE = 4096; +static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720; +static const int MIN_FREQ = 28; +static const int MAX_FREQ = 3520; +static const int MAX_FILTER_WIDTH = 20; + +static const int kChromaFilterSize = 5; +static const double kChromaFilterCoefficients[] = { 0.25, 0.75, 1.0, 0.75, 0.25 }; + +int main(int argc, char **argv) +{ + if (argc < 3) { + cerr << "Usage: " << argv[0] << " AUDIOFILE IMAGEFILE\n"; + return 1; + } + + string file_name(argv[1]); + cout << "Loading file " << file_name << "\n"; + + Decoder decoder(file_name); + if (!decoder.Open()) { + cerr << "ERROR: " << decoder.LastError() << "\n"; + return 2; + } + + const int numBands = 72; + Chromaprint::Image image(numBands); + Chromaprint::ImageBuilder image_builder(&image); + Chromaprint::Spectrum chroma(numBands, MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &image_builder); + Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, &chroma); + Chromaprint::AudioProcessor processor(SAMPLE_RATE, &fft); + + processor.Reset(decoder.SampleRate(), decoder.Channels()); + decoder.Decode(&processor); + processor.Flush(); + + //Chromaprint::ExportTextImage(&image, argv[2]); + Chromaprint::ExportImage(&image, argv[2], 0.5); + + return 0; +} + From 60a317477a716eaa8ed4d864d188c9e3d48ccf73 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 6 Jan 2012 15:56:20 +0000 Subject: [PATCH 18/40] Add debian copyright for chromaprint. (cherry picked from commit eabe8935bc2b297e5453eac8aeaac512a8c01ba1) --- debian/copyright | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/debian/copyright b/debian/copyright index fde23fc18..eb93792c7 100644 --- a/debian/copyright +++ b/debian/copyright @@ -110,6 +110,10 @@ Files: 3rdparty/sha2/* Copyright: 2000-2001, Aaron D. Gifford License: BSD +Files: 3rdparty/chromaprint/* +Copyright: 2010, Lukas Lalinsky +License: LGPL-2.1 + License: LGPL-2.1 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 2.1, as From 0036f3443695ac860f5b1cd9dd5c33e032ed4ed2 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 6 Jan 2012 15:57:51 +0000 Subject: [PATCH 19/40] Build & link against Chromaprint. (cherry picked from commit b9eec4ce38a0afc6b3399b3e5308fc256266e67d) --- CMakeLists.txt | 1 + src/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index a524a0645..5b214be2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -366,6 +366,7 @@ add_subdirectory(3rdparty/universalchardet) add_subdirectory(tests) add_subdirectory(dist) add_subdirectory(tools/ultimate_lyrics_parser) +add_subdirectory(3rdparty/chromaprint) option(WITH_DEBIAN OFF) if(WITH_DEBIAN) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4ef5790b6..52b0bb4d5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -961,6 +961,7 @@ add_dependencies(clementine_lib pot) target_link_libraries(clementine_lib chardet + chromaprint_p echoprint sha2 ${ECHONEST_LIBRARIES} From b9a6e1f7f1e5db54e9e8b482953ef8d515fd2754 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 6 Jan 2012 15:58:46 +0000 Subject: [PATCH 20/40] Add Chromaprinter class to generate fingerprint from gstreamer PCM output. (cherry picked from commit 423295b01e6b238e39edff375f5dd9f396b4d2e8) --- src/CMakeLists.txt | 1 + src/musicbrainz/chromaprinter.cpp | 233 ++++++++++++++++++++++++++++++ src/musicbrainz/chromaprinter.h | 68 +++++++++ 3 files changed, 302 insertions(+) create mode 100644 src/musicbrainz/chromaprinter.cpp create mode 100644 src/musicbrainz/chromaprinter.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 52b0bb4d5..6bc094ce9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -180,6 +180,7 @@ set(SOURCES library/librarywatcher.cpp library/sqlrow.cpp + musicbrainz/chromaprinter.cpp musicbrainz/echoprinter.cpp musicbrainz/fingerprinter.cpp musicbrainz/musicbrainzclient.cpp diff --git a/src/musicbrainz/chromaprinter.cpp b/src/musicbrainz/chromaprinter.cpp new file mode 100644 index 000000000..aadfce9b1 --- /dev/null +++ b/src/musicbrainz/chromaprinter.cpp @@ -0,0 +1,233 @@ +/* This file is part of Clementine. + Copyright 2010, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#include "chromaprinter.h" + +#include +#include +#include +#include + +#include "3rdparty/chromaprint/src/chromaprint.h" + +#include "core/logging.h" +#include "core/timeconstants.h" + + +Chromaprinter::Chromaprinter(const QString& filename) + : filename_(filename), + event_loop_(NULL), + convert_element_(NULL), + finishing_(false) +{ + buffer_.open(QIODevice::WriteOnly); +} + +Chromaprinter::~Chromaprinter() { +} + +GstElement* Chromaprinter::CreateElement(const QString &factory_name, + GstElement *bin) { + GstElement* ret = gst_element_factory_make( + factory_name.toAscii().constData(), + factory_name.toAscii().constData()); + + if (ret && bin) + gst_bin_add(GST_BIN(bin), ret); + + if (!ret) { + qLog(Warning) << "Couldn't create the gstreamer element" << factory_name; + } + + return ret; +} + +QString Chromaprinter::CreateFingerprint() { + GMainContext* context = g_main_context_new(); + g_main_context_push_thread_default(context); + event_loop_ = g_main_loop_new(context, FALSE); + + pipeline_ = gst_pipeline_new("pipeline"); + GstElement* src = CreateElement("filesrc", pipeline_); + GstElement* decode = CreateElement("decodebin2", pipeline_); + GstElement* convert = CreateElement("audioconvert", pipeline_); + GstElement* resample = CreateElement("audioresample", pipeline_); + GstElement* sink = CreateElement("appsink", pipeline_); + + if (!src || !decode || !convert || !resample || !sink) { + return QString(); + } + + convert_element_ = convert; + + // Connect the elements + gst_element_link_many(src, decode, NULL); + gst_element_link_many(convert, resample, NULL); + + // Chromaprint expects mono floats at a sample rate of 11025Hz. + GstCaps* caps = gst_caps_new_simple( + "audio/x-raw-int", + "width", G_TYPE_INT, 16, + "channels", G_TYPE_INT, 1, + "rate", G_TYPE_INT, 11025, + NULL); + gst_element_link_filtered(resample, sink, caps); + gst_caps_unref(caps); + + GstAppSinkCallbacks callbacks; + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.new_buffer = NewBufferCallback; + gst_app_sink_set_callbacks(reinterpret_cast(sink), &callbacks, this, NULL); + g_object_set(G_OBJECT(sink), "sync", FALSE, NULL); + g_object_set(G_OBJECT(sink), "emit-signals", TRUE, NULL); + + // Set the filename + g_object_set(src, "location", filename_.toLocal8Bit().constData(), NULL); + + // Connect signals + g_signal_connect(decode, "new-decoded-pad", G_CALLBACK(NewPadCallback), this); + gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallbackSync, this); + guint bus_callback_id = gst_bus_add_watch(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallback, this); + + QTime time; + time.start(); + + // Start playing + gst_element_set_state(pipeline_, GST_STATE_PLAYING); + + g_main_loop_run(event_loop_); + g_main_loop_unref(event_loop_); + g_main_context_unref(context); + + int decode_time = time.restart(); + + buffer_.close(); + QByteArray data = buffer_.data(); + + ChromaprintContext* chromaprint = chromaprint_new(CHROMAPRINT_ALGORITHM_DEFAULT); + chromaprint_start(chromaprint, 11025, 1); + chromaprint_feed(chromaprint, reinterpret_cast(data.data()), data.size() / 2); + chromaprint_finish(chromaprint); + + void* fprint = NULL; + int size = 0; + int ret = chromaprint_get_raw_fingerprint(chromaprint, &fprint, &size); + QByteArray fingerprint; + if (ret == 1) { + void* encoded = NULL; + int encoded_size = 0; + chromaprint_encode_fingerprint( + fprint, size, CHROMAPRINT_ALGORITHM_DEFAULT, &encoded, &encoded_size, 1); + + fingerprint.append(reinterpret_cast(encoded), encoded_size); + + chromaprint_dealloc(fprint); + chromaprint_dealloc(encoded); + } + int codegen_time = time.elapsed(); + + qLog(Debug) << "Decode time:" << decode_time << "Codegen time:" << codegen_time; + + qLog(Debug) << "Chromaprint:" << fingerprint; + + // Cleanup + gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), NULL, NULL); + g_source_remove(bus_callback_id); + gst_object_unref(pipeline_); + + return fingerprint; +} + +void Chromaprinter::NewPadCallback(GstElement*, GstPad* pad, gboolean, gpointer data) { + Chromaprinter* instance = reinterpret_cast(data); + GstPad* const audiopad = gst_element_get_pad(instance->convert_element_, "sink"); + + if (GST_PAD_IS_LINKED(audiopad)) { + qLog(Warning) << "audiopad is already linked, unlinking old pad"; + gst_pad_unlink(audiopad, GST_PAD_PEER(audiopad)); + } + + gst_pad_link(pad, audiopad); + gst_object_unref(audiopad); +} + +void Chromaprinter::ReportError(GstMessage* msg) { + GError* error; + gchar* debugs; + + gst_message_parse_error(msg, &error, &debugs); + QString message = QString::fromLocal8Bit(error->message); + + g_error_free(error); + free(debugs); + + qLog(Error) << "Error processing" << filename_ << ":" << message; +} + +gboolean Chromaprinter::BusCallback(GstBus*, GstMessage* msg, gpointer data) { + Chromaprinter* instance = reinterpret_cast(data); + + switch (GST_MESSAGE_TYPE(msg)) { + case GST_MESSAGE_ERROR: + instance->ReportError(msg); + g_main_loop_quit(instance->event_loop_); + break; + + default: + break; + } + return GST_BUS_DROP; +} + +GstBusSyncReply Chromaprinter::BusCallbackSync(GstBus*, GstMessage* msg, gpointer data) { + Chromaprinter* instance = reinterpret_cast(data); + + switch (GST_MESSAGE_TYPE(msg)) { + case GST_MESSAGE_EOS: + g_main_loop_quit(instance->event_loop_); + break; + + case GST_MESSAGE_ERROR: + instance->ReportError(msg); + g_main_loop_quit(instance->event_loop_); + break; + + default: + break; + } + return GST_BUS_PASS; +} + +GstFlowReturn Chromaprinter::NewBufferCallback(GstAppSink* app_sink, gpointer self) { + Chromaprinter* me = reinterpret_cast(self); + if (me->finishing_) { + return GST_FLOW_OK; + } + + GstBuffer* buffer = gst_app_sink_pull_buffer(app_sink); + me->buffer_.write(reinterpret_cast(buffer->data), buffer->size); + gst_buffer_unref(buffer); + + gint64 pos = 0; + GstFormat format = GST_FORMAT_TIME; + gboolean ret = gst_element_query_position(me->pipeline_, &format, &pos); + if (ret && pos > 30 * kNsecPerSec) { + me->finishing_ = true; + g_main_loop_quit(me->event_loop_); + } + return GST_FLOW_OK; +} diff --git a/src/musicbrainz/chromaprinter.h b/src/musicbrainz/chromaprinter.h new file mode 100644 index 000000000..1362579b1 --- /dev/null +++ b/src/musicbrainz/chromaprinter.h @@ -0,0 +1,68 @@ +/* This file is part of Clementine. + Copyright 2010, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#ifndef CHROMAPRINTER_H +#define CHROMAPRINTER_H + +#include +#include +#include + +#include +#include + +class QEventLoop; + +class Chromaprinter { + // Creates a Chromaprint fingerprint from a song. + // Uses GStreamer to open and decode the file as PCM data and passes this + // to Chromaprint's code generator. The generated code can be used to identify + // a song via Acoustid. + // You should create one Chromaprinter for each file you want to fingerprint. + // This class works well with QtConcurrentMap. + +public: + Chromaprinter(const QString& filename); + ~Chromaprinter(); + + // Creates a fingerprint from the song. This method is blocking, so you want + // to call it in another thread. Returns an empty string if no fingerprint + // could be created. + QString CreateFingerprint(); + +private: + GstElement* CreateElement(const QString& factory_name, GstElement* bin = NULL); + + void ReportError(GstMessage* message); + + static void NewPadCallback(GstElement*, GstPad* pad, gboolean, gpointer data); + static gboolean BusCallback(GstBus*, GstMessage* msg, gpointer data); + static GstBusSyncReply BusCallbackSync(GstBus*, GstMessage* msg, gpointer data); + static GstFlowReturn NewBufferCallback(GstAppSink* app_sink, gpointer self); + +private: + QString filename_; + GMainLoop* event_loop_; + + GstElement* convert_element_; + GstElement* pipeline_; + + QBuffer buffer_; + bool finishing_; +}; + +#endif // CHROMAPRINTER_H From dcae3d933c7a9c4b2d291360ba98cfbe1cdfd7bb Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 6 Jan 2012 16:31:29 +0000 Subject: [PATCH 21/40] * Use Chromaprinter instead of OFA fingerprinter. * Send fingerprint to Acoustid instead of MusicDNS. * Retrieve MBID instead of PUID and send to Musicbrainz. (cherry picked from commit db83c411c27a91ddaabb283c3fd44dbb0c9b4530) --- src/musicbrainz/chromaprinter.cpp | 2 - src/musicbrainz/musicbrainzclient.cpp | 6 +-- src/musicbrainz/musicbrainzclient.h | 8 ++-- src/musicbrainz/musicdnsclient.cpp | 63 ++++++++++++++++----------- src/musicbrainz/musicdnsclient.h | 6 +-- src/musicbrainz/tagfetcher.cpp | 7 +-- 6 files changed, 52 insertions(+), 40 deletions(-) diff --git a/src/musicbrainz/chromaprinter.cpp b/src/musicbrainz/chromaprinter.cpp index aadfce9b1..b040295f4 100644 --- a/src/musicbrainz/chromaprinter.cpp +++ b/src/musicbrainz/chromaprinter.cpp @@ -142,8 +142,6 @@ QString Chromaprinter::CreateFingerprint() { qLog(Debug) << "Decode time:" << decode_time << "Codegen time:" << codegen_time; - qLog(Debug) << "Chromaprint:" << fingerprint; - // Cleanup gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), NULL, NULL); g_source_remove(bus_callback_id); diff --git a/src/musicbrainz/musicbrainzclient.cpp b/src/musicbrainz/musicbrainzclient.cpp index d8a847b67..e4bf58276 100644 --- a/src/musicbrainz/musicbrainzclient.cpp +++ b/src/musicbrainz/musicbrainzclient.cpp @@ -35,14 +35,14 @@ MusicBrainzClient::MusicBrainzClient(QObject* parent) { } -void MusicBrainzClient::Start(int id, const QString& puid) { +void MusicBrainzClient::Start(int id, const QString& mbid) { typedef QPair Param; QList parameters; parameters << Param("type", "xml") - << Param("puid", puid); + << Param("inc", "artist+releases"); - QUrl url(kTrackUrl); + QUrl url(kTrackUrl + mbid); url.setQueryItems(parameters); QNetworkRequest req(url); diff --git a/src/musicbrainz/musicbrainzclient.h b/src/musicbrainz/musicbrainzclient.h index 25bda0c7e..21c59bfa4 100644 --- a/src/musicbrainz/musicbrainzclient.h +++ b/src/musicbrainz/musicbrainzclient.h @@ -30,8 +30,8 @@ class QNetworkReply; class MusicBrainzClient : public QObject { Q_OBJECT - // Gets metadata for a particular PUID. - // A PUID is created from a fingerprint using MusicDnsClient. + // Gets metadata for a particular MBID. + // An MBID is created from a fingerprint using MusicDnsClient. // You can create one MusicBrainzClient and make multiple requests using it. // IDs are provided by the caller when a request is started and included in // the Finished signal - they have no meaning to MusicBrainzClient. @@ -52,8 +52,8 @@ public: // Starts a request and returns immediately. Finished() will be emitted // later with the same ID. - void Start(int id, const QString& puid); - void StartDiscIdRequest(const QString& puid); + void Start(int id, const QString& mbid); + void StartDiscIdRequest(const QString& discid); // Cancels the request with the given ID. Finished() will never be emitted // for that ID. Does nothing if there is no request with the given ID. diff --git a/src/musicbrainz/musicdnsclient.cpp b/src/musicbrainz/musicdnsclient.cpp index bd777d86e..c09b773d1 100644 --- a/src/musicbrainz/musicdnsclient.cpp +++ b/src/musicbrainz/musicdnsclient.cpp @@ -16,15 +16,18 @@ */ #include "musicdnsclient.h" -#include "core/network.h" #include #include -#include -#include -const char* MusicDnsClient::kClientId = "c44f70e49000dd7c0d1388bff2bf4152"; -const char* MusicDnsClient::kUrl = "http://ofa.musicdns.org/ofa/1/track"; +#include + +#include "core/logging.h" +#include "core/network.h" +#include "core/timeconstants.h" + +const char* MusicDnsClient::kClientId = "qsZGpeLx"; +const char* MusicDnsClient::kUrl = "http://api.acoustid.org/v2/lookup"; const int MusicDnsClient::kDefaultTimeout = 5000; // msec MusicDnsClient::MusicDnsClient(QObject* parent) @@ -42,20 +45,11 @@ void MusicDnsClient::Start(int id, const QString& fingerprint, int duration_msec typedef QPair Param; QList parameters; - parameters << Param("alb", "unknown") - << Param("art", "unknown") - << Param("brt", "0") - << Param("cid", kClientId) - << Param("cvr", QString("%1 %2").arg(QCoreApplication::applicationName(), - QCoreApplication::applicationVersion())) - << Param("dur", QString::number(duration_msec)) - << Param("fmt", "unknown") - << Param("fpt", fingerprint) - << Param("gnr", "unknown") - << Param("rmd", "1") - << Param("tnm", "0") - << Param("ttl", "unknown") - << Param("yrr", "0"); + parameters << Param("format", "json") + << Param("client", kClientId) + << Param("duration", QString::number(duration_msec / kMsecPerSec)) + << Param("meta", "recordingids") + << Param("fingerprint", fingerprint); QUrl url(kUrl); url.setQueryItems(parameters); @@ -95,12 +89,31 @@ void MusicDnsClient::RequestFinished() { return; } - QXmlStreamReader reader(reply); - while (!reader.atEnd()) { - if (reader.readNext() == QXmlStreamReader::StartElement && reader.name() == "puid") { - QString puid = reader.attributes().value("id").toString(); - emit Finished(id, puid); - return; + QJson::Parser parser; + bool ok = false; + QVariantMap result = parser.parse(reply, &ok).toMap(); + if (!ok) { + emit Finished(id, QString()); + return; + } + + QString status = result["status"].toString(); + if (status != "ok") { + emit Finished(id, QString()); + return; + } + QVariantList results = result["results"].toList(); + foreach (const QVariant& v, results) { + QVariantMap r = v.toMap(); + if (r.contains("recordings")) { + QVariantList recordings = r["recordings"].toList(); + foreach (const QVariant& recording, recordings) { + QVariantMap o = recording.toMap(); + if (o.contains("id")) { + emit Finished(id, o["id"].toString()); + return; + } + } } } diff --git a/src/musicbrainz/musicdnsclient.h b/src/musicbrainz/musicdnsclient.h index 0e79280b6..0d92db9c9 100644 --- a/src/musicbrainz/musicdnsclient.h +++ b/src/musicbrainz/musicdnsclient.h @@ -29,9 +29,9 @@ class QNetworkReply; class MusicDnsClient : public QObject { Q_OBJECT - // Gets a PUID from an OFA fingerprint. + // Gets a MBID from a Chromaprint fingerprint. // A fingerprint identifies one particular encoding of a song and is created - // by Fingerprinter. A PUID identifies the actual song and can be passed to + // by Fingerprinter. An MBID identifies the actual song and can be passed to // Musicbrainz to get metadata. // You can create one MusicDnsClient and make multiple requests using it. // IDs are provided by the caller when a request is started and included in @@ -56,7 +56,7 @@ public: void CancelAll(); signals: - void Finished(int id, const QString& puid); + void Finished(int id, const QString& mbid); private slots: void RequestFinished(); diff --git a/src/musicbrainz/tagfetcher.cpp b/src/musicbrainz/tagfetcher.cpp index 30f7740fb..a87d2b398 100644 --- a/src/musicbrainz/tagfetcher.cpp +++ b/src/musicbrainz/tagfetcher.cpp @@ -15,10 +15,11 @@ along with Clementine. If not, see . */ -#include "fingerprinter.h" +#include "tagfetcher.h" + +#include "chromaprinter.h" #include "musicbrainzclient.h" #include "musicdnsclient.h" -#include "tagfetcher.h" #include "core/timeconstants.h" #include @@ -37,7 +38,7 @@ TagFetcher::TagFetcher(QObject* parent) } QString TagFetcher::GetFingerprint(const Song& song) { - return Fingerprinter(song.url().toLocalFile()).CreateFingerprint(); + return Chromaprinter(song.url().toLocalFile()).CreateFingerprint(); } void TagFetcher::StartFetch(const SongList& songs) { From 915e9e3d64fbe36b2c6c20f885920130abc8ed0d Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 6 Jan 2012 16:40:08 +0000 Subject: [PATCH 22/40] Remove old OFA fingerprinter. (cherry picked from commit f241124b1d81032951e7c6d856247727870b686a) --- dist/macdeploy.py | 3 - dist/windows/clementine.nsi.in | 6 +- src/CMakeLists.txt | 1 - src/musicbrainz/fingerprinter.cpp | 187 ------------------------------ src/musicbrainz/fingerprinter.h | 67 ----------- src/ui/edittagdialog.cpp | 6 - src/ui/mainwindow.cpp | 6 - 7 files changed, 2 insertions(+), 274 deletions(-) delete mode 100644 src/musicbrainz/fingerprinter.cpp delete mode 100644 src/musicbrainz/fingerprinter.h diff --git a/dist/macdeploy.py b/dist/macdeploy.py index 8036cf1d2..797dabebe 100755 --- a/dist/macdeploy.py +++ b/dist/macdeploy.py @@ -76,9 +76,6 @@ GSTREAMER_PLUGINS=[ # Icecast support 'libgsticydemux.so', - # Fingerprinting support - 'libgstofa.so', - # CD support 'libgstcdio.so', ] diff --git a/dist/windows/clementine.nsi.in b/dist/windows/clementine.nsi.in index 36ed436de..60fbd367d 100644 --- a/dist/windows/clementine.nsi.in +++ b/dist/windows/clementine.nsi.in @@ -87,10 +87,12 @@ Section "Delete old files" oldfiles Delete "$INSTDIR\libgstrtsp-0.10.dll" Delete "$INSTDIR\libgstsdp-0.10.dll" Delete "$INSTDIR\libgsttag-0.10.dll" + Delete "$INSTDIR\libofa.dll" Delete "$INSTDIR\libxml2.dll" Delete "$INSTDIR\z.dll" Delete "$INSTDIR\gstreamer-plugins\libgstasfdemux.dll" Delete "$INSTDIR\gstreamer-plugins\libgstffmpeg-gpl.dll" + Delete "$INSTDIR\gstreamer-plugins\libgstofa.dll" Delete "$INSTDIR\gstreamer-plugins\libgstqueue2.dll" Delete "$INSTDIR\gstreamer-plugins\libgstsoup.dll" @@ -149,7 +151,6 @@ Section "Clementine" Clementine File "libmad.dll" File "libmms-0.dll" File "libmp3lame-0.dll" - File "libofa.dll" File "libogg-0.dll" File "liboil-0.3-0.dll" File "liborc-0.4-0.dll" @@ -267,7 +268,6 @@ Section "Gstreamer plugins" gstreamer-plugins File "/oname=libgstmad.dll" "gstreamer-plugins\libgstmad.dll" File "/oname=libgstmms.dll" "gstreamer-plugins\libgstmms.dll" File "/oname=libgstmpegaudioparse.dll" "gstreamer-plugins\libgstmpegaudioparse.dll" - File "/oname=libgstofa.dll" "gstreamer-plugins\libgstofa.dll" File "/oname=libgstogg.dll" "gstreamer-plugins\libgstogg.dll" File "/oname=libgstqtdemux.dll" "gstreamer-plugins\libgstqtdemux.dll" File "/oname=libgstreplaygain.dll" "gstreamer-plugins\libgstreplaygain.dll" @@ -990,7 +990,6 @@ Section "Uninstall" Delete "$INSTDIR\libmad.dll" Delete "$INSTDIR\libmms-0.dll" Delete "$INSTDIR\libmp3lame-0.dll" - Delete "$INSTDIR\libofa.dll" Delete "$INSTDIR\libogg-0.dll" Delete "$INSTDIR\liboil-0.3-0.dll" Delete "$INSTDIR\liborc-0.4-0.dll" @@ -1048,7 +1047,6 @@ Section "Uninstall" Delete "$INSTDIR\gstreamer-plugins\libgstmad.dll" Delete "$INSTDIR\gstreamer-plugins\libgstmms.dll" Delete "$INSTDIR\gstreamer-plugins\libgstmpegaudioparse.dll" - Delete "$INSTDIR\gstreamer-plugins\libgstofa.dll" Delete "$INSTDIR\gstreamer-plugins\libgstogg.dll" Delete "$INSTDIR\gstreamer-plugins\libgstqtdemux.dll" Delete "$INSTDIR\gstreamer-plugins\libgstreplaygain.dll" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6bc094ce9..36aa4ede7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -182,7 +182,6 @@ set(SOURCES musicbrainz/chromaprinter.cpp musicbrainz/echoprinter.cpp - musicbrainz/fingerprinter.cpp musicbrainz/musicbrainzclient.cpp musicbrainz/musicdnsclient.cpp musicbrainz/tagfetcher.cpp diff --git a/src/musicbrainz/fingerprinter.cpp b/src/musicbrainz/fingerprinter.cpp deleted file mode 100644 index ab353c68e..000000000 --- a/src/musicbrainz/fingerprinter.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* This file is part of Clementine. - Copyright 2010, David Sansome - - Clementine is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Clementine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Clementine. If not, see . -*/ - -#include "fingerprinter.h" -#include "core/logging.h" - -#include -#include -#include - -Fingerprinter::Fingerprinter(const QString& filename) - : filename_(filename), - event_loop_(NULL), - convert_element_(NULL) -{ -} - -Fingerprinter::~Fingerprinter() { -} - -bool Fingerprinter::GstreamerHasOfa() { - GstElementFactory* factory = gst_element_factory_find("ofa"); - if (!factory) { - return false; - } - - gst_object_unref(factory); - return true; -} - -GstElement* Fingerprinter::CreateElement(const QString &factory_name, - GstElement *bin) { - GstElement* ret = gst_element_factory_make( - factory_name.toAscii().constData(), - factory_name.toAscii().constData()); - - if (ret && bin) - gst_bin_add(GST_BIN(bin), ret); - - if (!ret) { - qLog(Warning) << "Couldn't create the gstreamer element" << factory_name; - } - - return ret; -} - -QString Fingerprinter::CreateFingerprint() { - GMainContext* context = g_main_context_new(); - g_main_context_push_thread_default(context); - event_loop_ = g_main_loop_new(context, FALSE); - - GstElement* pipeline = gst_pipeline_new("pipeline"); - GstElement* src = CreateElement("filesrc", pipeline); - GstElement* decode = CreateElement("decodebin2", pipeline); - GstElement* convert = CreateElement("audioconvert", pipeline); - GstElement* ofa = CreateElement("ofa", pipeline); - GstElement* sink = CreateElement("fakesink", pipeline); - - if (!src || !decode || !convert || !ofa || !sink) { - return QString(); - } - - convert_element_ = convert; - - // Connect the elements - gst_element_link_many(src, decode, NULL); - gst_element_link_many(convert, ofa, sink, NULL); - - // Set the filename - g_object_set(src, "location", filename_.toLocal8Bit().constData(), NULL); - - // Connect signals - g_signal_connect(decode, "new-decoded-pad", G_CALLBACK(NewPadCallback), this); - gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline)), BusCallbackSync, this); - guint bus_callback_id = gst_bus_add_watch(gst_pipeline_get_bus(GST_PIPELINE(pipeline)), BusCallback, this); - - // Start playing - gst_element_set_state(pipeline, GST_STATE_PLAYING); - - g_main_loop_run(event_loop_); - g_main_loop_unref(event_loop_); - g_main_context_unref(context); - - // Cleanup - gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline)), NULL, NULL); - g_source_remove(bus_callback_id); - gst_object_unref(pipeline); - - return fingerprint_; -} - -void Fingerprinter::NewPadCallback(GstElement*, GstPad* pad, gboolean, gpointer data) { - Fingerprinter* instance = reinterpret_cast(data); - GstPad* const audiopad = gst_element_get_pad(instance->convert_element_, "sink"); - - if (GST_PAD_IS_LINKED(audiopad)) { - qLog(Warning) << "audiopad is already linked, unlinking old pad"; - gst_pad_unlink(audiopad, GST_PAD_PEER(audiopad)); - } - - gst_pad_link(pad, audiopad); - gst_object_unref(audiopad); -} - -void Fingerprinter::ReportError(GstMessage* msg) { - GError* error; - gchar* debugs; - - gst_message_parse_error(msg, &error, &debugs); - QString message = QString::fromLocal8Bit(error->message); - - g_error_free(error); - free(debugs); - - qLog(Error) << "Error processing" << filename_ << ":" << message; -} - -gboolean Fingerprinter::BusCallback(GstBus*, GstMessage* msg, gpointer data) { - Fingerprinter* instance = reinterpret_cast(data); - - switch (GST_MESSAGE_TYPE(msg)) { - case GST_MESSAGE_ERROR: - instance->ReportError(msg); - g_main_loop_quit(instance->event_loop_); - break; - - case GST_MESSAGE_TAG: - instance->TagMessageReceived(msg); - break; - - default: - break; - } - return GST_BUS_DROP; -} - -GstBusSyncReply Fingerprinter::BusCallbackSync(GstBus*, GstMessage* msg, gpointer data) { - Fingerprinter* instance = reinterpret_cast(data); - - switch (GST_MESSAGE_TYPE(msg)) { - case GST_MESSAGE_EOS: - g_main_loop_quit(instance->event_loop_); - break; - - case GST_MESSAGE_ERROR: - instance->ReportError(msg); - g_main_loop_quit(instance->event_loop_); - break; - - case GST_MESSAGE_TAG: - instance->TagMessageReceived(msg); - break; - - default: - break; - } - return GST_BUS_PASS; -} - -void Fingerprinter::TagMessageReceived(GstMessage* message) { - GstTagList* taglist = NULL; - gst_message_parse_tag(message, &taglist); - - gchar* data = NULL; - bool success = gst_tag_list_get_string(taglist, "ofa-fingerprint", &data); - - if (success && data) { - fingerprint_ = QString::fromUtf8(data); - g_free(data); - } - - gst_tag_list_free(taglist); -} diff --git a/src/musicbrainz/fingerprinter.h b/src/musicbrainz/fingerprinter.h deleted file mode 100644 index e49da8f2d..000000000 --- a/src/musicbrainz/fingerprinter.h +++ /dev/null @@ -1,67 +0,0 @@ -/* This file is part of Clementine. - Copyright 2010, David Sansome - - Clementine is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Clementine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Clementine. If not, see . -*/ - -#ifndef FINGERPRINTER_H -#define FINGERPRINTER_H - -#include -#include - -#include - -class QEventLoop; - -class Fingerprinter { - // Creates an OFA fingerprint from a song. - // Uses GStreamer to open and decode the file, also uses gstreamer's ofa - // element to generate the fingerprint. The fingerprint identifies one - // particular encoding of a song. Pass the fingerprint to MusicDNS to - // identify it. - // You should create one Fingerprinter for each file you want to fingerprint. - // This class works well with QtConcurrentMap. - -public: - Fingerprinter(const QString& filename); - ~Fingerprinter(); - - // Checks if this gstreamer installation has the required ofa plugin. - static bool GstreamerHasOfa(); - - // Creates a fingerprint from the song. This method is blocking, so you want - // to call it in another thread. Returns an empty string if no fingerprint - // could be created. - QString CreateFingerprint(); - -private: - GstElement* CreateElement(const QString& factory_name, GstElement* bin = NULL); - - void ReportError(GstMessage* message); - void TagMessageReceived(GstMessage* message); - - static void NewPadCallback(GstElement*, GstPad* pad, gboolean, gpointer data); - static gboolean BusCallback(GstBus*, GstMessage* msg, gpointer data); - static GstBusSyncReply BusCallbackSync(GstBus*, GstMessage* msg, gpointer data); - -private: - QString filename_; - QString fingerprint_; - GMainLoop* event_loop_; - - GstElement* convert_element_; -}; - -#endif // FINGERPRINTER_H diff --git a/src/ui/edittagdialog.cpp b/src/ui/edittagdialog.cpp index 5ada0a35d..fbdea511d 100644 --- a/src/ui/edittagdialog.cpp +++ b/src/ui/edittagdialog.cpp @@ -25,7 +25,6 @@ #include "covers/coverproviders.h" #include "library/library.h" #include "library/librarybackend.h" -#include "musicbrainz/fingerprinter.h" #include "playlist/playlistdelegates.h" #include "ui/albumcoverchoicecontroller.h" #include "ui/coverfromurldialog.h" @@ -728,11 +727,6 @@ void EditTagDialog::ResetPlayCounts() { } void EditTagDialog::FetchTag() { - if (!Fingerprinter::GstreamerHasOfa()) { - QMessageBox::warning(this, tr("Error"), tr("Your gstreamer installation is missing the 'ofa' plugin. This is required for automatic tag fetching. Try installing the 'gstreamer-plugins-bad' package.")); - return; - } - const QModelIndexList sel = ui_->song_list->selectionModel()->selectedIndexes(); SongList songs; diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 35845efa6..d159ecc0c 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -54,7 +54,6 @@ #include "library/librarydirectorymodel.h" #include "library/libraryfilterwidget.h" #include "library/libraryviewcontainer.h" -#include "musicbrainz/fingerprinter.h" #include "musicbrainz/tagfetcher.h" #include "playlist/playlistbackend.h" #include "playlist/playlist.h" @@ -2117,11 +2116,6 @@ void MainWindow::Exit() { } void MainWindow::AutoCompleteTags() { - if (!Fingerprinter::GstreamerHasOfa()) { - QMessageBox::warning(this, tr("Error"), tr("Your gstreamer installation is missing the 'ofa' plugin. This is required for automatic tag fetching. Try installing the 'gstreamer-plugins-bad' package.")); - return; - } - // Create the tag fetching stuff if it hasn't been already if (!tag_fetcher_) { tag_fetcher_.reset(new TagFetcher); From ba7b73656d5af7a66935b350332ffb57cd7aeacf Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 6 Jan 2012 16:42:22 +0000 Subject: [PATCH 23/40] Remove echoprint. (cherry picked from commit 598948d16e157028b615760da735fc3902d0095a) --- 3rdparty/echoprint-codegen/.gitignore | 3 - 3rdparty/echoprint-codegen/AUTHORS | 26 -- 3rdparty/echoprint-codegen/CMakeLists.txt | 25 -- 3rdparty/echoprint-codegen/LICENSE | 44 --- 3rdparty/echoprint-codegen/README.md | 93 ----- .../src/AudioBufferInput.cxx | 29 -- .../echoprint-codegen/src/AudioBufferInput.h | 30 -- .../src/AudioStreamInput.cxx | 132 ------- .../echoprint-codegen/src/AudioStreamInput.h | 97 ----- 3rdparty/echoprint-codegen/src/Base64.cxx | 141 -------- 3rdparty/echoprint-codegen/src/Base64.h | 10 - 3rdparty/echoprint-codegen/src/Codegen.cxx | 96 ----- 3rdparty/echoprint-codegen/src/Codegen.h | 48 --- 3rdparty/echoprint-codegen/src/Common.h | 55 --- 3rdparty/echoprint-codegen/src/File.h | 50 --- .../echoprint-codegen/src/Fingerprint.cxx | 239 ------------- 3rdparty/echoprint-codegen/src/Fingerprint.h | 45 --- 3rdparty/echoprint-codegen/src/Makefile | 61 ---- .../echoprint-codegen/src/MatrixUtility.cxx | 52 --- .../echoprint-codegen/src/MatrixUtility.h | 31 -- 3rdparty/echoprint-codegen/src/Metadata.cxx | 33 -- 3rdparty/echoprint-codegen/src/Metadata.h | 38 -- 3rdparty/echoprint-codegen/src/Params.h | 23 -- .../echoprint-codegen/src/SubbandAnalysis.cxx | 70 ---- .../echoprint-codegen/src/SubbandAnalysis.h | 65 ---- 3rdparty/echoprint-codegen/src/Whitening.cxx | 109 ------ 3rdparty/echoprint-codegen/src/Whitening.h | 41 --- .../src/echoprint-codegen-ios/README.md | 22 -- .../echoprint-codegen-ios.xcconfig | 8 - .../project.pbxproj | 302 ---------------- .../contents.xcworkspacedata | 7 - .../echoprint-codegen-ios-Prefix.pch | 4 - 3rdparty/echoprint-codegen/src/main.cxx | 334 ------------------ 3rdparty/echoprint-codegen/src/win_funcs.h | 34 -- 3rdparty/echoprint-codegen/src/win_unistd.h | 37 -- CMakeLists.txt | 1 - src/CMakeLists.txt | 2 - src/musicbrainz/echoprinter.cpp | 213 ----------- src/musicbrainz/echoprinter.h | 68 ---- 39 files changed, 2718 deletions(-) delete mode 100644 3rdparty/echoprint-codegen/.gitignore delete mode 100644 3rdparty/echoprint-codegen/AUTHORS delete mode 100644 3rdparty/echoprint-codegen/CMakeLists.txt delete mode 100644 3rdparty/echoprint-codegen/LICENSE delete mode 100644 3rdparty/echoprint-codegen/README.md delete mode 100644 3rdparty/echoprint-codegen/src/AudioBufferInput.cxx delete mode 100644 3rdparty/echoprint-codegen/src/AudioBufferInput.h delete mode 100644 3rdparty/echoprint-codegen/src/AudioStreamInput.cxx delete mode 100644 3rdparty/echoprint-codegen/src/AudioStreamInput.h delete mode 100644 3rdparty/echoprint-codegen/src/Base64.cxx delete mode 100644 3rdparty/echoprint-codegen/src/Base64.h delete mode 100644 3rdparty/echoprint-codegen/src/Codegen.cxx delete mode 100644 3rdparty/echoprint-codegen/src/Codegen.h delete mode 100644 3rdparty/echoprint-codegen/src/Common.h delete mode 100644 3rdparty/echoprint-codegen/src/File.h delete mode 100644 3rdparty/echoprint-codegen/src/Fingerprint.cxx delete mode 100644 3rdparty/echoprint-codegen/src/Fingerprint.h delete mode 100644 3rdparty/echoprint-codegen/src/Makefile delete mode 100644 3rdparty/echoprint-codegen/src/MatrixUtility.cxx delete mode 100644 3rdparty/echoprint-codegen/src/MatrixUtility.h delete mode 100644 3rdparty/echoprint-codegen/src/Metadata.cxx delete mode 100644 3rdparty/echoprint-codegen/src/Metadata.h delete mode 100644 3rdparty/echoprint-codegen/src/Params.h delete mode 100644 3rdparty/echoprint-codegen/src/SubbandAnalysis.cxx delete mode 100644 3rdparty/echoprint-codegen/src/SubbandAnalysis.h delete mode 100644 3rdparty/echoprint-codegen/src/Whitening.cxx delete mode 100644 3rdparty/echoprint-codegen/src/Whitening.h delete mode 100644 3rdparty/echoprint-codegen/src/echoprint-codegen-ios/README.md delete mode 100644 3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios.xcconfig delete mode 100644 3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios.xcodeproj/project.pbxproj delete mode 100644 3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios/echoprint-codegen-ios-Prefix.pch delete mode 100644 3rdparty/echoprint-codegen/src/main.cxx delete mode 100644 3rdparty/echoprint-codegen/src/win_funcs.h delete mode 100644 3rdparty/echoprint-codegen/src/win_unistd.h delete mode 100644 src/musicbrainz/echoprinter.cpp delete mode 100644 src/musicbrainz/echoprinter.h diff --git a/3rdparty/echoprint-codegen/.gitignore b/3rdparty/echoprint-codegen/.gitignore deleted file mode 100644 index 945fb3e8e..000000000 --- a/3rdparty/echoprint-codegen/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.o -*.dylib -*.so diff --git a/3rdparty/echoprint-codegen/AUTHORS b/3rdparty/echoprint-codegen/AUTHORS deleted file mode 100644 index 250aaf604..000000000 --- a/3rdparty/echoprint-codegen/AUTHORS +++ /dev/null @@ -1,26 +0,0 @@ -See the LICENSE file for important license information. - -Whitening, SubbandAnalysis, Fingerprint -Dan Ellis -Brian Whitman - -AudioBufferInput, AudioStreamInput, Codegen, Common, File, MatrixUtility, Metadata -Tristan Jehan -Paul Lamere -Jason Sundram -Brian Whitman - -Murmurhash2 -Austin Appleby - -Base64 -Rene Nyffenegger - -Contributors -Alastair Porter -efsavage -alsuren -artgillespie -yhorng -divan - diff --git a/3rdparty/echoprint-codegen/CMakeLists.txt b/3rdparty/echoprint-codegen/CMakeLists.txt deleted file mode 100644 index c34464075..000000000 --- a/3rdparty/echoprint-codegen/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -set(ECHOPRINT-SOURCES - src/AudioBufferInput.cxx - src/AudioStreamInput.cxx - src/Base64.cxx - src/Codegen.cxx - src/Fingerprint.cxx - src/MatrixUtility.cxx - src/Metadata.cxx - src/SubbandAnalysis.cxx - src/Whitening.cxx -) - -include_directories(${Boost_INCLUDE_DIRS}) -add_library(echoprint STATIC ${ECHOPRINT-SOURCES}) - -set_target_properties(echoprint PROPERTIES - COMPILE_DEFINITIONS "BOOST_UBLAS_NDEBUG;NDEBUG") - -if(NOT WIN32) - set_target_properties(echoprint PROPERTIES - COMPILE_FLAGS "-O3 -fPIC") -else(NOT WIN32) - set_target_properties(echoprint PROPERTIES - COMPILE_FLAGS "-O3") -endif(NOT WIN32) diff --git a/3rdparty/echoprint-codegen/LICENSE b/3rdparty/echoprint-codegen/LICENSE deleted file mode 100644 index ce4461450..000000000 --- a/3rdparty/echoprint-codegen/LICENSE +++ /dev/null @@ -1,44 +0,0 @@ -echoprint-codegen is open source software licensed under the "MIT License" -More information about the MIT License: http://en.wikipedia.org/wiki/MIT_License - -Copyright (c) 2011 The Echo Nest Corporation - -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. - - -libcodegen makes use of the following pieces of software: - -- Murmurhash by Austin Appleby (Public Domain / MIT) -http://sites.google.com/site/murmurhash/ - -- Boost (Boost Software License) -http://www.boost.org/users/license.html - -- Base64.cpp and Base64.h, see source files for license -Copyright (C) 2004-2008 René Nyffenegger - - -codegen (the example binary that the makefile also builds) makes use of libcodegen and: - -- Taglib (LGPL) -http://developer.kde.org/~wheeler/taglib.html - -- ffmpeg (via system shell, you must install ffmpeg on your own) -http://www.ffmpeg.org/legal.html - diff --git a/3rdparty/echoprint-codegen/README.md b/3rdparty/echoprint-codegen/README.md deleted file mode 100644 index 285e82025..000000000 --- a/3rdparty/echoprint-codegen/README.md +++ /dev/null @@ -1,93 +0,0 @@ -# Codegen for Echoprint - -Echoprint is an open source music fingerprint and resolving framework powered by the [The Echo Nest](http://the.echonest.com/ "The Echo Nest"). The [code generator](http://github.com/echonest/echoprint-codegen "echoprint-codegen") (library to convert PCM samples from a microphone or file into Echoprint codes) is open source (MIT licensed) and free for any use. The [server component](http://github.com/echonest/echoprint-server "echoprint-server") that stores and resolves queries is open source (Apache 2 licensed) and free for any use. The [data for resolving to millions of songs](http://echoprint.me/data "Echoprint Data") is free for any use provided any changes or additions are merged back to the community. - -[Read more about Echoprint here](http://echoprint.me) - -There are two modes of operation of the Echoprint codegen: - -1. the codegen library (libcodegen) is meant to be linked into code that passes it a buffer of PCM data and will output a code string. - -2. the codegen binary runs standalone, accepts filenames as inputs and runs in a multithreaded worker mode. - -## Requirements - -### For libcodegen - -* Boost >= 1.35 -* zlib - -### Additional requirements for the codegen binary - -* [TagLib](http://developer.kde.org/~wheeler/taglib.html "TagLib") -* ffmpeg - this is called via shell and is not linked into codegen - -On Ubuntu or Debian you can install these dependencies with: - - sudo apt-get install ffmpeg libboost1.42-dev libtag1-dev zlib1g-dev -On OS-X with homebrew you can use: - - brew install ffmpeg boost taglib - -## Notes about libcodegen: - -Code generation takes a buffer of floating point PCM data sampled at 11025 Hz and mono. - - Codegen * pCodegen = new Codegen(const float* pcm, uint numSamples, int start_offset); - - pcm: a buffer of floats, mono, 11025 Hz - numSamples: the number of samples - start_offset: creates a hint to the server on where the sample is taken from in the original file if known - - string code = pCodegen->getCodeString(); - -The code string is just a base64 encoding of a zlib compression of the original code string, which is a hex encoded series of ASCII numbers. See API/fp.py in echoprint-server for decoding help. - -You only need to query for 20 seconds of audio to get a result. - -## Notes about the codegen binary - -The makefile builds an example code generator that uses libcodegen, called "codegen." This code generator has more features -- it will output ID3 tag information and uses ffmpeg to decode any type of file. If you don't need to compile libcodegen into your app you can rely on this. Note that you need to have ffmpeg installed and accessible on your path for this to work. - - ./echoprint-codegen billie_jean.mp3 10 30 - -Will take 30 seconds of audio from 10 seconds into the file and output JSON suitable for querying: - - {"metadata":{"artist":"Michael jackson", "release":"800 chansons des annes 80", "title":"Billie jean", "genre":"", "bitrate":192, "sample_rate":44100, "seconds":294, "filename":"billie_jean.mp3", "samples_decoded":220598, "given_duration":30, "start_offset":10, "version":4.00}, "code_count":846, "code":"JxVlIuNwzAMQ1fxCDL133+xo1rnGqNAEcWy/ERa2aKeZmW... - -You can POST this JSON directly to the Echo Nest's [song/identify](http://developer.echonest.com/docs/v4/song.html#identify "song/identify") (who has an Echoprint server booted), for example: - - curl -F "query=@post_string" http://developer.echonest.com/api/v4/song/identify?api_key=YOUR_KEY - {"fp_lookup_time_ms": 21, "results": [{"songID": "SOAFVGQ1280ED4E371", "match_type": "fp", "title": "Billie Jean", "artist": "Michael Jackson", "artistID": "ARXPPEY1187FB51DF4", "score": 63, "release": "Thriller"}] - (you can also use GET, see the API description) - -Or you can host your own [Echoprint server](http://github.com/echonest/echoprint-server "echoprint-server") and ingest or query to that. - -Codegen also runs in a multithreaded mode for bulk resolving: - - ./echoprint-codegen -s 10 30 < file_list - -Will compute codes for every file in file_list for 30 seconds starting at 10 seconds. (It tries to be smart about the number of threads to use.) It will output a JSON list. Note that song/identify can accept lists in the JSON, which will be faster than sending each code one at a time. The "tag" parameter is added to each code dictionary to match the resolving material. - -## Statistics - -### Speed - -Codegen scans audio at roughly 250x real time per processor after decoding and resampling to 11025 Hz. This means a full song can be scanned in less than 0.5s on an average computer, and an amount of audio suitable for querying (30s) can be scanned in less than 0.04s. - -Decoding from MP3 will be the bottleneck for most implementations. Decoders like mpg123 or ffmpeg can decode 30s mp3 audio to 11025 PCM in under 0.10s. - - clump:echoprint-codegen bwhitman$ time mpg123 -q -s -4 -n 1200 song.mp3 > /dev/null - real 0m0.079s - user 0m0.067s - sys 0m0.007s - -### Accuracy - -Look at http://echoprint.me for information on the accuracy of the echoprint system. - -## FAQ - -Q: I get "Couldn't decode any samples with: ffmpeg" when running codegen - -A: When running the example code generator (echoprint-codegen) make sure ffmpeg is accessible to your path. Try running ffmpeg filename.mp3 on the file you are testing the code generator with. If it doesn't work, codegen won't work. diff --git a/3rdparty/echoprint-codegen/src/AudioBufferInput.cxx b/3rdparty/echoprint-codegen/src/AudioBufferInput.cxx deleted file mode 100644 index 9ef6cdb60..000000000 --- a/3rdparty/echoprint-codegen/src/AudioBufferInput.cxx +++ /dev/null @@ -1,29 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - -#include -#include -#include - - -#include "AudioBufferInput.h" - -AudioBufferInput::AudioBufferInput() { } - -void AudioBufferInput::SetBuffer(const float* pBuffer, uint numSamples) { - _NumberSamples = numSamples; - _pSamples = new float[_NumberSamples]; // base-class destructor will clean this up. - memcpy(_pSamples, pBuffer, numSamples*sizeof(float)); -} - -void AudioBufferInput::SaveBuffer(const char*filename) { - FILE *out = fopen(filename,"wb"); - fwrite(&_NumberSamples, sizeof(int), 1, out); - uint mn = 1; - fwrite(&mn, sizeof(int), 1, out); - fwrite(_pSamples, 4, _NumberSamples, out); - fclose(out); -} - diff --git a/3rdparty/echoprint-codegen/src/AudioBufferInput.h b/3rdparty/echoprint-codegen/src/AudioBufferInput.h deleted file mode 100644 index c60dfdbe5..000000000 --- a/3rdparty/echoprint-codegen/src/AudioBufferInput.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - - -#include "Common.h" -#include -#include -#ifndef AUDIOBUFFERINPUT_H -#define AUDIOBUFFERINPUT_H -#include "Params.h" -#include "AudioStreamInput.h" - - -class AudioBufferInput : public AudioStreamInput { -public: - AudioBufferInput(); - std::string GetName() {return "direct buffer";} - void SaveBuffer(const char*filename); - void SetBuffer(const float* pBuffer, uint numSamples); -protected: - std::string GetCommandLine(const char*){return "";} -private: -}; -#endif - - - diff --git a/3rdparty/echoprint-codegen/src/AudioStreamInput.cxx b/3rdparty/echoprint-codegen/src/AudioStreamInput.cxx deleted file mode 100644 index 9033b076e..000000000 --- a/3rdparty/echoprint-codegen/src/AudioStreamInput.cxx +++ /dev/null @@ -1,132 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - - -#include -#include -#include -#include -#include -#ifndef _WIN32 -#include -#define POPEN_MODE "r" -#else -#include "win_unistd.h" -#include -#define POPEN_MODE "rb" -#endif -#include - -#include "AudioStreamInput.h" -#include "Common.h" -#include "Params.h" - -using std::string; - -namespace FFMPEG { - // Do we think FFmpeg will read this as an audio file? - bool IsAudioFile(const char* pFileName) { - static const char* supportedExtensions[] = {".mp3", ".m4a", ".mp4", ".aif", ".aiff", ".flac", ".au", ".wav", ".aac", ".flv"}; - // Not an exhaustive list. ogg and rm could be added if tested. - for (uint i = 0; i < NELEM(supportedExtensions); i++) { - if (File::ends_with(pFileName, supportedExtensions[i])) - return true; - } - return false; - } -} - -bool AudioStreamInput::IsSupported(const char *path) { - return true; // Take a crack at anything, by default. The worst thing that will happen is that we fail. -} - -AudioStreamInput::AudioStreamInput() : _pSamples(NULL), _NumberSamples(0), _Offset_s(0), _Seconds(0) {} - -AudioStreamInput::~AudioStreamInput() { - if (_pSamples != NULL) - delete [] _pSamples, _pSamples = NULL; -} - - -bool AudioStreamInput::ProcessFile(const char* filename, int offset_s/*=0*/, int seconds/*=0*/) { - if (!File::Exists(filename) || !IsSupported(filename)) - return false; - - _Offset_s = offset_s; - _Seconds = seconds; - std::string message = GetCommandLine(filename); - - FILE* fp = popen(message.c_str(), POPEN_MODE); - bool ok = (fp != NULL); - if (ok) - { - bool did_work = ProcessFilePointer(fp); - bool succeeded = !pclose(fp); - ok = did_work && succeeded; - } - else - fprintf(stderr, "AudioStreamInput::ProcessFile can't open %s\n", filename); - - return ok; -} - -// reads raw signed 16-bit shorts from a file -bool AudioStreamInput::ProcessRawFile(const char* rawFilename) { - FILE* fp = fopen(rawFilename, "r"); // TODO: Windows - bool ok = (fp != NULL); - if (ok) - { - ok = ProcessFilePointer(fp); - fclose(fp); - } - - return ok; -} - -// reads raw signed 16-bit shorts from stdin, for example: -// ffmpeg -i fille.mp3 -f s16le -ac 1 -ar 11025 - | TestAudioSTreamInput -bool AudioStreamInput::ProcessStandardInput(void) { - // TODO - Windows will explodey at not setting O_BINARY on stdin. - return ProcessFilePointer(stdin); -} - -bool AudioStreamInput::ProcessFilePointer(FILE* pFile) { - std::vector vChunks; - uint nSamplesPerChunk = (uint) Params::AudioStreamInput::SamplingRate * Params::AudioStreamInput::SecondsPerChunk; - uint samplesRead = 0; - do { - short* pChunk = new short[nSamplesPerChunk]; - samplesRead = fread(pChunk, sizeof (short), nSamplesPerChunk, pFile); - _NumberSamples += samplesRead; - vChunks.push_back(pChunk); - } while (samplesRead > 0); - - // Convert from shorts to 16-bit floats and copy into sample buffer. - uint sampleCounter = 0; - _pSamples = new float[_NumberSamples]; - uint samplesLeft = _NumberSamples; - for (uint i = 0; i < vChunks.size(); i++) - { - short* pChunk = vChunks[i]; - uint numSamples = samplesLeft < nSamplesPerChunk ? samplesLeft : nSamplesPerChunk; - - for (uint j = 0; j < numSamples; j++) - _pSamples[sampleCounter++] = (float) pChunk[j] / 32768.0f; - - samplesLeft -= numSamples; - delete [] pChunk, vChunks[i] = NULL; - } - assert(samplesLeft == 0); - - int error = ferror(pFile); - bool success = error == 0; - - if (!success) - perror("ProcessFilePointer error"); - return success; -} - - diff --git a/3rdparty/echoprint-codegen/src/AudioStreamInput.h b/3rdparty/echoprint-codegen/src/AudioStreamInput.h deleted file mode 100644 index 651cb327a..000000000 --- a/3rdparty/echoprint-codegen/src/AudioStreamInput.h +++ /dev/null @@ -1,97 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - -#ifndef AUDIOSTREAMINPUT_H -#define AUDIOSTREAMINPUT_H -#include "Common.h" -#include "Params.h" -#include -#include -#include -#include "File.h" -#if defined(_WIN32) && !defined(__MINGW32__) -#define and && -#define snprintf _snprintf -#endif - -class AudioStreamInput { -public: - AudioStreamInput(); - virtual ~AudioStreamInput(); - virtual bool ProcessFile(const char* filename, int offset_s=0, int seconds=0); - virtual std::string GetName() = 0; - bool ProcessRawFile(const char* rawFilename); - bool ProcessStandardInput(void); - bool ProcessFilePointer(FILE* pFile); - int getNumSamples() const {return _NumberSamples;} - const float* getSamples() {return _pSamples;} - double getDuration() { return (double)getNumSamples() / Params::AudioStreamInput::SamplingRate; } - virtual bool IsSupported(const char* pFileName); //Everything ffmpeg can do, by default - int GetOffset() const { return _Offset_s;} - int GetSeconds() const { return _Seconds;} -protected: - - virtual std::string GetCommandLine(const char* filename) = 0; - static bool ends_with(const char *s, const char *ends_with); - float* _pSamples; - uint _NumberSamples; - int _Offset_s; - int _Seconds; - -}; - -class StdinStreamInput : public AudioStreamInput { -public: - std::string GetName(){return "stdin";}; -protected: - bool IsSupported(const char* pFileName){ return (std::string("stdin") == pFileName);}; - bool ProcessFile(const char* filename){ return ProcessStandardInput();} - virtual std::string GetCommandLine(const char* filename){return "";} // hack -}; - -class FfmpegStreamInput : public AudioStreamInput { -public: - std::string GetName(){return "ffmpeg";}; -protected: - std::string GetCommandLine(const char* filename) { - // TODO: Windows - char message[4096] = {0}; - if (_Offset_s == 0 and _Seconds == 0) - snprintf(message, NELEM(message), "ffmpeg -i \"%s\" -ac %d -ar %d -f s16le - 2>/dev/null", - filename, Params::AudioStreamInput::Channels, (uint) Params::AudioStreamInput::SamplingRate); - else - snprintf(message, NELEM(message), "ffmpeg -i \"%s\" -ac %d -ar %d -f s16le -t %d -ss %d - 2>/dev/null", - filename, Params::AudioStreamInput::Channels, (uint) Params::AudioStreamInput::SamplingRate, _Seconds, _Offset_s); - - return std::string(message); - } -}; - -namespace FFMPEG { - bool IsAudioFile(const char* pFileName); -}; - -class Mpg123StreamInput : public AudioStreamInput { -public: - std::string GetName(){return "mpg123";}; -protected: - #define FRAMES_PER_SECOND 38.2813f - bool IsSupported(const char* pFileName){ return File::ends_with(pFileName, ".mp3");}; - std::string GetCommandLine(const char* filename) { - char message[4096] = {0}; - if (_Offset_s == 0 and _Seconds == 0) - snprintf(message, NELEM(message), "mpg123 --quiet --singlemix --stdout --rate %d \"%s\"", - (uint) Params::AudioStreamInput::SamplingRate, filename); - else - snprintf(message, NELEM(message), "mpg123 --quiet --singlemix --stdout --rate %d --skip %d --frames %d \"%s\"", - (uint) Params::AudioStreamInput::SamplingRate, (uint)(_Offset_s * FRAMES_PER_SECOND) /* unprecise */, (uint)ceilf(_Seconds * FRAMES_PER_SECOND) /* unprecise */, filename); - return std::string(message); - } -}; - -#endif - - diff --git a/3rdparty/echoprint-codegen/src/Base64.cxx b/3rdparty/echoprint-codegen/src/Base64.cxx deleted file mode 100644 index ab3aef614..000000000 --- a/3rdparty/echoprint-codegen/src/Base64.cxx +++ /dev/null @@ -1,141 +0,0 @@ -/* - base64.cpp and base64.h - - Copyright (C) 2004-2008 René Nyffenegger - - This source code is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this source code must not be misrepresented; you must not - claim that you wrote the original source code. If you use this source code - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original source code. - - 3. This notice may not be removed or altered from any source distribution. - - René Nyffenegger rene.nyffenegger@adp-gmbh.ch - -*/ - -#include "Base64.h" -#include - -static const std::string base64_chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - -static const std::string base64_chars_url = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789-_"; - - - -static inline bool is_base64(unsigned char c) { - return (isalnum(c) || (c == '+') || (c == '/')); -} - -static inline bool is_base64_url(unsigned char c) { - return (isalnum(c) || (c == '-') || (c == '_')); -} - -std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len, bool url) { - std::string ret; - int i = 0; - int j = 0; - unsigned char char_array_3[3]; - unsigned char char_array_4[4]; - - while (in_len--) { - char_array_3[i++] = *(bytes_to_encode++); - if (i == 3) { - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for(i = 0; (i <4) ; i++) { - if (url) - ret += base64_chars_url[char_array_4[i]]; - else - ret += base64_chars[char_array_4[i]]; - } - i = 0; - } - } - - if (i) - { - for(j = i; j < 3; j++) - char_array_3[j] = '\0'; - - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for (j = 0; (j < i + 1); j++){ - if (url) - ret += base64_chars_url[char_array_4[j]]; - else - ret += base64_chars[char_array_4[j]]; - } - while((i++ < 3)) - ret += '='; - - } - - return ret; - -} - -std::string base64_decode(std::string const& encoded_string) { - int in_len = encoded_string.size(); - int i = 0; - int j = 0; - int in_ = 0; - unsigned char char_array_4[4], char_array_3[3]; - std::string ret; - - while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { - char_array_4[i++] = encoded_string[in_]; in_++; - if (i ==4) { - for (i = 0; i <4; i++) - char_array_4[i] = base64_chars.find(char_array_4[i]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (i = 0; (i < 3); i++) - ret += char_array_3[i]; - i = 0; - } - } - - if (i) { - for (j = i; j <4; j++) - char_array_4[j] = 0; - - for (j = 0; j <4; j++) - char_array_4[j] = base64_chars.find(char_array_4[j]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; - } - - return ret; -} - diff --git a/3rdparty/echoprint-codegen/src/Base64.h b/3rdparty/echoprint-codegen/src/Base64.h deleted file mode 100644 index dbfe7aaca..000000000 --- a/3rdparty/echoprint-codegen/src/Base64.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef BASE64_H -#define BASE64_H - -#include - -std::string base64_encode(unsigned char const* , unsigned int len, bool url); -std::string base64_decode(std::string const& s); - -#endif - diff --git a/3rdparty/echoprint-codegen/src/Codegen.cxx b/3rdparty/echoprint-codegen/src/Codegen.cxx deleted file mode 100644 index 0b7f8c3e1..000000000 --- a/3rdparty/echoprint-codegen/src/Codegen.cxx +++ /dev/null @@ -1,96 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - -#include -#include -#include -#include -#include "Codegen.h" -#include "AudioBufferInput.h" -#include "Fingerprint.h" -#include "Whitening.h" -#include "SubbandAnalysis.h" -#include "Fingerprint.h" -#include "Common.h" - -#include "Base64.h" -#include - -#define VERSION 4.11 - -using namespace std; - -float Codegen::getVersion() { - return VERSION; -} - -Codegen::Codegen(const float* pcm, uint numSamples, int start_offset) { - if (Params::AudioStreamInput::MaxSamples < (uint)numSamples) - throw std::runtime_error("File was too big\n"); - - Whitening *pWhitening = new Whitening(pcm, numSamples); - pWhitening->Compute(); - - AudioBufferInput *pAudio = new AudioBufferInput(); - pAudio->SetBuffer(pWhitening->getWhitenedSamples(), pWhitening->getNumSamples()); - - SubbandAnalysis *pSubbandAnalysis = new SubbandAnalysis(pAudio); - pSubbandAnalysis->Compute(); - - Fingerprint *pFingerprint = new Fingerprint(pSubbandAnalysis, start_offset); - pFingerprint->Compute(); - - _CodeString = createCodeString(pFingerprint->getCodes()); - _NumCodes = pFingerprint->getCodes().size(); - - delete pFingerprint; - delete pSubbandAnalysis; - delete pWhitening; - delete pAudio; -} - -string Codegen::createCodeString(vector vCodes) { - if (vCodes.size() < 3) { - return ""; - } - std::ostringstream codestream; - codestream << std::setfill('0') << std::hex; - for (uint i = 0; i < vCodes.size(); i++) - codestream << std::setw(5) << vCodes[i].frame; - - for (uint i = 0; i < vCodes.size(); i++) { - int hash = vCodes[i].code; - codestream << std::setw(5) << hash; - } - return compress(codestream.str()); -} - - -string Codegen::compress(const string& s) { - long max_compressed_length = s.size()*2; - unsigned char *compressed = new unsigned char[max_compressed_length]; - - // zlib the code string - z_stream stream; - stream.next_in = (Bytef*)(unsigned char*)s.c_str(); - stream.avail_in = (uInt)s.size(); - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - stream.opaque = (voidpf)0; - deflateInit(&stream, Z_DEFAULT_COMPRESSION); - do { - stream.next_out = compressed; - stream.avail_out = max_compressed_length; - if(deflate(&stream, Z_FINISH) == Z_STREAM_END) break; - } while (stream.avail_out == 0); - uint compressed_length = stream.total_out; - deflateEnd(&stream); - - // base64 the zlib'd code string - string encoded = base64_encode(compressed, compressed_length, true); - delete [] compressed; - return encoded; -} diff --git a/3rdparty/echoprint-codegen/src/Codegen.h b/3rdparty/echoprint-codegen/src/Codegen.h deleted file mode 100644 index bb2499969..000000000 --- a/3rdparty/echoprint-codegen/src/Codegen.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - -#ifndef CODEGEN_H -#define CODEGEN_H - -// Entry point for generating codes from PCM data. - -#include -#include -#include - -#ifdef _MSC_VER - #ifdef CODEGEN_EXPORTS - #define CODEGEN_API __declspec(dllexport) - #pragma message("Exporting codegen.dll") - #else - #define CODEGEN_API __declspec(dllimport) - #pragma message("Importing codegen.dll") - #endif -#else - #define CODEGEN_API -#endif - -class Fingerprint; -class SubbandAnalysis; -struct FPCode; - -class CODEGEN_API Codegen { -public: - Codegen(const float* pcm, unsigned int numSamples, int start_offset); - - std::string getCodeString(){return _CodeString;} - int getNumCodes(){return _NumCodes;} - static float getVersion(); -private: - Fingerprint* computeFingerprint(SubbandAnalysis *pSubbandAnalysis, int start_offset); - std::string createCodeString(std::vector vCodes); - - std::string compress(const std::string& s); - std::string _CodeString; - int _NumCodes; -}; - -#endif diff --git a/3rdparty/echoprint-codegen/src/Common.h b/3rdparty/echoprint-codegen/src/Common.h deleted file mode 100644 index ccce7d06a..000000000 --- a/3rdparty/echoprint-codegen/src/Common.h +++ /dev/null @@ -1,55 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - -#ifndef COMMON_H -#define COMMON_H - - - -#include -#ifndef _WIN32 - #include -#else -#include "win_funcs.h" -#include -/* for STL*/ - #ifdef max - #undef max - #endif - #ifdef min - #undef min - #endif -#include -#endif -#include -#include -#include - - -#ifndef NULL -#define NULL 0 -#endif - - -// Returns the current date in seconds. The precision is in microseconds. -static inline double now (void) { - struct timeval tv; - double now; - gettimeofday (&tv, NULL); - now = 1e-6 * tv.tv_usec + tv.tv_sec; - return now; -} - -typedef unsigned int uint; -#define NELEM(array) (sizeof(array) / sizeof(array[0])) - -#ifndef _WIN32 -#define EN_ARRAY(type,var,size) type var[size] -#else -#define EN_ARRAY(type,var,size) type* var = (type*) _alloca((size)*sizeof(type)) -#endif - -#endif diff --git a/3rdparty/echoprint-codegen/src/File.h b/3rdparty/echoprint-codegen/src/File.h deleted file mode 100644 index e277f34b4..000000000 --- a/3rdparty/echoprint-codegen/src/File.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - -#ifndef FILE_H -#define FILE_H -#include -#ifdef _WIN32 -#include "win_unistd.h" -#endif -/* -This makes file writing a bit easier (makes sure we don't forget to fclose, basically). Use it like this: - -bool WriteStuffToFile(const char* filename) -{ - File f(filename); - if (f) - fprintf(f, "stuff I want to print: %s", stuff); - return f; // success/failure -} -*/ -class File { -public: - File(const char* filename){_f = fopen(filename, "w");}; - ~File(){fclose(_f); _f = NULL;} - operator bool(){return _f != NULL;} - operator FILE*(){return _f;} - static bool Exists(const char* filename){return (access(filename, F_OK) == 0);} - static bool ends_with(const char* filename, const char* ending) { - int nFilename = strlen(filename); - int nEnding = strlen(ending); - - bool same = false; - if (nEnding <= nFilename) { - const char* file_end = filename + strlen(filename) - strlen(ending); - - for (int i = 0; i < nEnding; i++) - if (tolower(file_end[i]) != tolower(ending[i])) return false; - - same = true; - } - return same; - } -private: - FILE* _f; -}; - -#endif diff --git a/3rdparty/echoprint-codegen/src/Fingerprint.cxx b/3rdparty/echoprint-codegen/src/Fingerprint.cxx deleted file mode 100644 index f5196963c..000000000 --- a/3rdparty/echoprint-codegen/src/Fingerprint.cxx +++ /dev/null @@ -1,239 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - -#include "Fingerprint.h" -#include "Params.h" -#include - -unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed ) { - // MurmurHash2, by Austin Appleby http://sites.google.com/site/murmurhash/ - // m and r are constants set by austin - const unsigned int m = 0x5bd1e995; - const int r = 24; - // Initialize the hash to a 'random' value - unsigned int h = seed ^ len; - // Mix 4 bytes at a time into the hash - const unsigned char * data = (const unsigned char *)key; - while(len >= 4) { - unsigned int k = *(unsigned int *)data; - k *= m; - k ^= k >> r; - k *= m; - h *= m; - h ^= k; - data += 4; - len -= 4; - } - - // Handle the last few bytes of the input array - switch(len) { - case 3: h ^= data[2] << 16; - case 2: h ^= data[1] << 8; - case 1: h ^= data[0]; - h *= m; - }; - - // Do a few final mixes of the hash to ensure the last few - // bytes are well-incorporated. - h ^= h >> 13; - h *= m; - h ^= h >> 15; - return h; -} - -Fingerprint::Fingerprint(SubbandAnalysis* pSubbandAnalysis, int offset) - : _pSubbandAnalysis(pSubbandAnalysis), _Offset(offset) { } - - -uint Fingerprint::adaptiveOnsets(int ttarg, matrix_u&out, uint*&onset_counter_for_band) { - // E is a sgram-like matrix of energies. - const float *pE; - int bands, frames, i, j, k; - int deadtime = 128; - double H[SUBBANDS],taus[SUBBANDS], N[SUBBANDS]; - int contact[SUBBANDS], lcontact[SUBBANDS], tsince[SUBBANDS]; - double overfact = 1.1; /* threshold rel. to actual peak */ - uint onset_counter = 0; - - matrix_f E = _pSubbandAnalysis->getMatrix(); - - // Take successive stretches of 8 subband samples and sum their energy under a hann window, then hop by 4 samples (50% window overlap). - int hop = 4; - int nsm = 8; - float ham[nsm]; - for(int i = 0 ; i != nsm ; i++) - ham[i] = .5 - .5*cos( (2.*M_PI/(nsm-1))*i); - - int nc = floor((float)E.size2()/(float)hop)-(floor((float)nsm/(float)hop)-1); - matrix_f Eb = matrix_f(nc, 8); - for(uint r=0;r= 2*nbn) { - for (int k = 0; k < nbn; ++k) { - xn += bn[k]*(pE[j-SUBBANDS*k] - pE[j-SUBBANDS*(2*nbn-k)]); - } - } - /* IIR part */ - xn = xn + a1*Y0[j]; - /* remember the last filtered level */ - Y0[j] = xn; - - contact[j] = (xn > H[j])? 1 : 0; - - if (contact[j] == 1 && lcontact[j] == 0) { - /* attach - record the threshold level unless we have one */ - if(N[j] == 0) { - N[j] = H[j]; - } - } - if (contact[j] == 1) { - /* update with new threshold */ - H[j] = xn * overfact; - } else { - /* apply decays */ - H[j] = H[j] * exp(-1.0/(double)taus[j]); - } - - if (contact[j] == 0 && lcontact[j] == 1) { - /* detach */ - if (onset_counter_for_band[j] > 0 && (int)out(j, onset_counter_for_band[j]-1) > i - deadtime) { - // overwrite last-written time - --onset_counter_for_band[j]; - --onset_counter; - } - out(j, onset_counter_for_band[j]++) = i; - ++onset_counter; - tsince[j] = 0; - } - ++tsince[j]; - if (tsince[j] > ttarg) { - taus[j] = taus[j] - 1; - if (taus[j] < 1) taus[j] = 1; - } else { - taus[j] = taus[j] + 1; - } - - if ( (contact[j] == 0) && (tsince[j] > deadtime)) { - /* forget the threshold where we recently hit */ - N[j] = 0; - } - lcontact[j] = contact[j]; - } - pE += bands; - } - - return onset_counter; -} - - -// dan is going to beat me if i call this "decimated_time_for_frame" like i want to -uint Fingerprint::quantized_time_for_frame_delta(uint frame_delta) { - double time_for_frame_delta = (double)frame_delta / ((double)Params::AudioStreamInput::SamplingRate / 32.0); - return ((int)floor((time_for_frame_delta * 1000.0) / (float)QUANTIZE_DT_S) * QUANTIZE_DT_S) / floor(QUANTIZE_DT_S*1000.0); -} - -uint Fingerprint::quantized_time_for_frame_absolute(uint frame) { - double time_for_frame = _Offset + (double)frame / ((double)Params::AudioStreamInput::SamplingRate / 32.0); - return ((int)rint((time_for_frame * 1000.0) / (float)QUANTIZE_A_S) * QUANTIZE_A_S) / floor(QUANTIZE_A_S*1000.0); -} - - -void Fingerprint::Compute() { - uint actual_codes = 0; - unsigned char hash_material[5]; - for(uint i=0;i<5;i++) hash_material[i] = 0; - uint * onset_counter_for_band; - matrix_u out; - uint onset_count = adaptiveOnsets(345, out, onset_counter_for_band); - _Codes.resize(onset_count*6); - - for(unsigned char band=0;band2) { - for(uint onset=0;onset 1) { - p[0][1] = (out(band,onset+1) - out(band,onset)); - p[1][1] = (out(band,onset+3) - out(band,onset+1)); - p[0][2] = (out(band,onset+2) - out(band,onset)); - p[1][2] = (out(band,onset+3) - out(band,onset+2)); - if(nhashes > 3) { - p[0][3] = (out(band,onset+1) - out(band,onset)); - p[1][3] = (out(band,onset+4) - out(band,onset+1)); - p[0][4] = (out(band,onset+2) - out(band,onset)); - p[1][4] = (out(band,onset+4) - out(band,onset+2)); - p[0][5] = (out(band,onset+3) - out(band,onset)); - p[1][5] = (out(band,onset+4) - out(band,onset+3)); - } - } - - // For each pair emit a code - for(uint k=0;k<6;k++) { - // Quantize the time deltas to 23ms - short time_delta0 = (short)quantized_time_for_frame_delta(p[0][k]); - short time_delta1 = (short)quantized_time_for_frame_delta(p[1][k]); - // Create a key from the time deltas and the band index - memcpy(hash_material+0, (const void*)&time_delta0, 2); - memcpy(hash_material+2, (const void*)&time_delta1, 2); - memcpy(hash_material+4, (const void*)&band, 1); - uint hashed_code = MurmurHash2(&hash_material, 5, HASH_SEED) & HASH_BITMASK; - - // Set the code alongside the time of onset - _Codes[actual_codes++] = FPCode(time_for_onset_ms_quantized, hashed_code); - //fprintf(stderr, "whee %d,%d: [%d, %d] (%d, %d), %d = %u at %d\n", actual_codes, k, time_delta0, time_delta1, p[0][k], p[1][k], band, hashed_code, time_for_onset_ms_quantized); - } - } - } - } - - _Codes.resize(actual_codes); - delete [] onset_counter_for_band; -} - - diff --git a/3rdparty/echoprint-codegen/src/Fingerprint.h b/3rdparty/echoprint-codegen/src/Fingerprint.h deleted file mode 100644 index cd4c784f5..000000000 --- a/3rdparty/echoprint-codegen/src/Fingerprint.h +++ /dev/null @@ -1,45 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - - -#ifndef FINGERPRINT_H -#define FINGERPRINT_H - -#include "Common.h" -#include "SubbandAnalysis.h" -#include "MatrixUtility.h" -#include - -#define HASH_SEED 0x9ea5fa36 -#define QUANTIZE_DT_S (256.0/11025.0) -#define QUANTIZE_A_S (256.0/11025.0) -#define HASH_BITMASK 0x000fffff -#define SUBBANDS 8 - -struct FPCode { - FPCode() : frame(0), code(0) {} - FPCode(uint f, int c) : frame(f), code(c) {} - uint frame; - uint code; -}; - -unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed ); - -class Fingerprint { -public: - uint quantized_time_for_frame_delta(uint frame_delta); - uint quantized_time_for_frame_absolute(uint frame); - Fingerprint(SubbandAnalysis* pSubbandAnalysis, int offset); - void Compute(); - uint adaptiveOnsets(int ttarg, matrix_u&out, uint*&onset_counter_for_band) ; - std::vector& getCodes(){return _Codes;} -protected: - SubbandAnalysis *_pSubbandAnalysis; - int _Offset; - std::vector _Codes; -}; - -#endif diff --git a/3rdparty/echoprint-codegen/src/Makefile b/3rdparty/echoprint-codegen/src/Makefile deleted file mode 100644 index ba62bfc78..000000000 --- a/3rdparty/echoprint-codegen/src/Makefile +++ /dev/null @@ -1,61 +0,0 @@ -UNAME := $(shell uname -s) -CXX=g++ -CC=gcc -#OPTFLAGS=-g -O0 -OPTFLAGS=-O3 -DBOOST_UBLAS_NDEBUG -DNDEBUG -CXXFLAGS=-Wall -I/usr/local/include/boost-1_35 `taglib-config --cflags` -fPIC $(OPTFLAGS) -CFLAGS=-Wall -fPIC $(OPTFLAGS) -LDFLAGS=`taglib-config --libs` -lz -lpthread $(OPTFLAGS) - -MODULES_LIB = \ - AudioBufferInput.o \ - AudioStreamInput.o \ - Base64.o \ - Codegen.o \ - Fingerprint.o \ - MatrixUtility.o \ - SubbandAnalysis.o \ - Whitening.o -MODULES = $(MODULES_LIB) Metadata.o - -all: libcodegen echoprint-codegen - -libcodegen: $(MODULES_LIB) - $(CXX) -shared -fPIC -o libcodegen.so $(MODULES_LIB) -lz -ifeq ($(UNAME),Darwin) - libtool -dynamic -flat_namespace -install_name libcodegen.4.1.1.dylib -lSystem -compatibility_version 4.1 -macosx_version_min 10.6 \ - -current_version 4.1.1 -o libcodegen.4.1.1.dylib -undefined suppress \ - $(MODULES_LIB) -framework vecLib -framework Accelerate -endif - -echoprint-codegen: $(MODULES) main.o - $(CXX) $(MODULES) $(LDFLAGS) main.o -o ../echoprint-codegen - -%.o: %.c %.h - $(CC) $(CFLAGS) -c -o $@ $< - -%.o: %.c - $(CC) $(CFLAGS) -c -o $@ $< - -%.o: %.cxx %.h - $(CXX) $(CXXFLAGS) -c -o $@ $< - -%.o: %.cxx - $(CXX) $(CXXFLAGS) -c -o $@ $< - -clean: - rm -f *.o ../echoprint-codegen - rm -f *.so -ifeq ($(UNAME),Darwin) - rm -f *.dylib -endif - -PREFIX ?= /usr/local -# todo: dylib -install: all - install ../echoprint-codegen $(PREFIX)/bin - install -d $(PREFIX)/include/echoprint - install -m 644 Codegen.h $(PREFIX)/include/echoprint - install -m 644 libcodegen.so $(PREFIX)/lib - -.PHONY: clean all libcodegen echoprint-codegen install \ No newline at end of file diff --git a/3rdparty/echoprint-codegen/src/MatrixUtility.cxx b/3rdparty/echoprint-codegen/src/MatrixUtility.cxx deleted file mode 100644 index 4e27c0d6f..000000000 --- a/3rdparty/echoprint-codegen/src/MatrixUtility.cxx +++ /dev/null @@ -1,52 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - - -#include "MatrixUtility.h" - -// http://www.boost.org/doc/libs/1_35_0/libs/numeric/ublas/doc/matrix.htm - -namespace MatrixUtility { - -bool TextFileOutput(const matrix_f& A, const char* filename) { - FILE *matrix_file = fopen(filename, "w"); - bool success = (matrix_file != NULL); - if (success) { - const float *d = &A.data()[0]; - for (uint i = 0; i < A.size1(); i++) { - for (uint j = 0; j < A.size2(); j++) - fprintf(matrix_file, "%2.3f ", d[i*A.size2() + j]); - - fprintf(matrix_file, "\n"); - } - fclose(matrix_file); - } - return success; -} - -bool FileOutput(const matrix_f& A, const char* filename) { - FILE *matrix_file = fopen(filename, "wb"); - bool success = (matrix_file != NULL); - if (success) { - uint mm = A.size1(); - uint mn = A.size2(); - fwrite(&mm, sizeof(int), 1, matrix_file); - fwrite(&mn, sizeof(int), 1, matrix_file); - - for (uint i = 0; i< A.size1(); i++) { - for(uint j=0;j -#include - -namespace ublas = boost::numeric::ublas; - -typedef ublas::matrix matrix_f; -typedef ublas::matrix matrix_u; - -typedef ublas::matrix_row matrix_row_f; -typedef ublas::matrix_row > const_matrix_row_f; -typedef ublas::matrix_column matrix_column_f; -typedef ublas::matrix_range matrix_range_f; - -namespace MatrixUtility { - inline uint rows(matrix_f A){ return A.size1();} - inline uint cols(matrix_f A){ return A.size2();} - bool FileOutput(const matrix_f& A, const char* filename); - bool TextFileOutput(const matrix_f& A, const char* filename); -} -#endif diff --git a/3rdparty/echoprint-codegen/src/Metadata.cxx b/3rdparty/echoprint-codegen/src/Metadata.cxx deleted file mode 100644 index f511aa294..000000000 --- a/3rdparty/echoprint-codegen/src/Metadata.cxx +++ /dev/null @@ -1,33 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - -#include "Metadata.h" -#include -#include -#include - -Metadata::Metadata(const string& file) : _Filename(file), _Artist(""), _Album(""), _Title(""), _Genre(""), _Bitrate(0), _SampleRate(0), _Seconds(0) { - if (file != "stdin") { - // TODO: Consider removing the path from the filename -- not sure if we can do this in a platform-independent way. - TagLib::FileRef f(_Filename.c_str()); - - TagLib::Tag* tag = f.isNull() ? NULL : f.tag(); - if (tag != NULL) { - _Artist = tag->artist().toCString(); - _Album = tag->album().toCString(); - _Title = tag->title().toCString(); - _Genre = tag->genre().toCString(); - } - - TagLib::AudioProperties* properties = f.isNull() ? NULL : f.audioProperties(); - if (properties != NULL) { - _Bitrate = properties->bitrate(); - _SampleRate = properties->sampleRate(); - _Seconds = properties->length(); - } - } -} - diff --git a/3rdparty/echoprint-codegen/src/Metadata.h b/3rdparty/echoprint-codegen/src/Metadata.h deleted file mode 100644 index 5f0fbcbe4..000000000 --- a/3rdparty/echoprint-codegen/src/Metadata.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - - -#ifndef METADATA_H -#define METADATA_H - - -#include -using std::string; - -class Metadata { -public: - Metadata(const std::string& file); - string Filename() {return _Filename;} - string Artist(){ return _Artist;} - string Album() { return _Album;} - string Title() { return _Title;} - string Genre() { return _Genre;} - int Bitrate() { return _Bitrate;} - int SampleRate(){ return _SampleRate;} - int Seconds() { return _Seconds;} -private: - string _Filename; - string _Artist; - string _Album; - string _Title; - string _Genre; - - int _Bitrate; - int _SampleRate; - int _Seconds; -}; -#endif - diff --git a/3rdparty/echoprint-codegen/src/Params.h b/3rdparty/echoprint-codegen/src/Params.h deleted file mode 100644 index 476f122e7..000000000 --- a/3rdparty/echoprint-codegen/src/Params.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - - -#ifndef PARAMS_H -#define PARAMS_H - -#include "Common.h" - -namespace Params { - namespace AudioStreamInput { - const float SamplingRate = 11025.0f; - const uint Channels = 1; - const float SecondsPerChunk = 10.0f; - const uint BytesPerSample = 4; // floats - const uint MaxSamples = 66977792; // TODO: Remove this, or set it intelligently, at least. Good for 32-bit analyzer. - } -} - -#endif diff --git a/3rdparty/echoprint-codegen/src/SubbandAnalysis.cxx b/3rdparty/echoprint-codegen/src/SubbandAnalysis.cxx deleted file mode 100644 index 55480e34e..000000000 --- a/3rdparty/echoprint-codegen/src/SubbandAnalysis.cxx +++ /dev/null @@ -1,70 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - -#include "SubbandAnalysis.h" -#include "AudioStreamInput.h" - -SubbandAnalysis::SubbandAnalysis(AudioStreamInput* pAudio) { - _pSamples = pAudio->getSamples(); - _NumSamples = pAudio->getNumSamples(); - Init(); -} - -SubbandAnalysis::SubbandAnalysis(const float* pSamples, uint numSamples) : - _pSamples(pSamples), _NumSamples(numSamples) { - Init(); -} - -SubbandAnalysis::~SubbandAnalysis() { -} - -void SubbandAnalysis::Init() { - // Calculate the analysis filter bank coefficients - _Mr = matrix_f(M_ROWS, M_COLS); - _Mi = matrix_f(M_ROWS, M_COLS); - for (uint i = 0; i < M_ROWS; ++i) { - for (uint k = 0; k < M_COLS; ++k) { - _Mr(i,k) = cos((2*i + 1)*(k-4)*(M_PI/16.0)); - _Mi(i,k) = sin((2*i + 1)*(k-4)*(M_PI/16.0)); - } - } -} - -void SubbandAnalysis::Compute() { - uint t, i, j; - - float Z[C_LEN]; - float Y[M_COLS]; - - _NumFrames = (_NumSamples - C_LEN + 1)/SUBBANDS; - assert(_NumFrames > 0); - - _Data = matrix_f(SUBBANDS, _NumFrames); - - for (t = 0; t < _NumFrames; ++t) { - for (i = 0; i < C_LEN; ++i) { - Z[i] = _pSamples[ t*SUBBANDS + i] * SubbandFilterBank::C[i]; - } - - for (i = 0; i < M_COLS; ++i) { - Y[i] = Z[i]; - } - for (i = 0; i < M_COLS; ++i) { - for (j = 1; j < M_ROWS; ++j) { - Y[i] += Z[i + M_COLS*j]; - } - } - for (i = 0; i < M_ROWS; ++i) { - float Dr = 0, Di = 0; - for (j = 0; j < M_COLS; ++j) { - Dr += _Mr(i,j) * Y[j]; - Di -= _Mi(i,j) * Y[j]; - } - _Data(i,t) = Dr*Dr + Di*Di; - } - } -} - diff --git a/3rdparty/echoprint-codegen/src/SubbandAnalysis.h b/3rdparty/echoprint-codegen/src/SubbandAnalysis.h deleted file mode 100644 index 68f00bf4f..000000000 --- a/3rdparty/echoprint-codegen/src/SubbandAnalysis.h +++ /dev/null @@ -1,65 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - -#ifndef SUBBANDANALYSIS_H -#define SUBBANDANALYSIS_H -#include "Common.h" -#include "Params.h" -#include "MatrixUtility.h" - -#define C_LEN 128 -#define SUBBANDS 8 -#define M_ROWS 8 -#define M_COLS 16 - -namespace SubbandFilterBank { - // 128pt, 1/8th band low-pass prototype subsampled from Table_analysis_window - static const float C[C_LEN] = { - 0.000000477, 0.000000954, 0.000001431, 0.000002384, 0.000003815, 0.000006199, 0.000009060, 0.000013828, - 0.000019550, 0.000027657, 0.000037670, 0.000049591, 0.000062943, 0.000076771, 0.000090599, 0.000101566, - -0.000108242, -0.000106812, -0.000095367, -0.000069618, -0.000027180, 0.000034332, 0.000116348, 0.000218868, - 0.000339031, 0.000472546, 0.000611782, 0.000747204, 0.000866413, 0.000954151, 0.000994205, 0.000971317, - -0.000868797, -0.000674248, -0.000378609, 0.000021458, 0.000522137, 0.001111031, 0.001766682, 0.002457142, - 0.003141880, 0.003771782, 0.004290581, 0.004638195, 0.004752159, 0.004573822, 0.004049301, 0.003134727, - -0.001800537, -0.000033379, 0.002161503, 0.004756451, 0.007703304, 0.010933399, 0.014358521, 0.017876148, - 0.021372318, 0.024725437, 0.027815342, 0.030526638, 0.032754898, 0.034412861, 0.035435200, 0.035780907, - -0.035435200, -0.034412861, -0.032754898, -0.030526638, -0.027815342, -0.024725437, -0.021372318, -0.017876148, - -0.014358521, -0.010933399, -0.007703304, -0.004756451, -0.002161503, 0.000033379, 0.001800537, 0.003134727, - -0.004049301, -0.004573822, -0.004752159, -0.004638195, -0.004290581, -0.003771782, -0.003141880, -0.002457142, - -0.001766682, -0.001111031, -0.000522137, -0.000021458, 0.000378609, 0.000674248, 0.000868797, 0.000971317, - -0.000994205, -0.000954151, -0.000866413, -0.000747204, -0.000611782, -0.000472546, -0.000339031, -0.000218868, - -0.000116348, -0.000034332, 0.000027180, 0.000069618, 0.000095367, 0.000106812, 0.000108242, 0.000101566, - -0.000090599, -0.000076771, -0.000062943, -0.000049591, -0.000037670, -0.000027657, -0.000019550, -0.000013828, - -0.000009060, -0.000006199, -0.000003815, -0.000002384, -0.000001431, -0.000000954, -0.000000477, 0}; -} - -class AudioStreamInput; - -class SubbandAnalysis { -public: - inline SubbandAnalysis() {}; - SubbandAnalysis(AudioStreamInput* pAudio); - SubbandAnalysis(const float* pSamples, uint numSamples); - virtual ~SubbandAnalysis(); - void Compute(); -public: - inline uint getNumFrames() const {return _NumFrames;} - inline uint getNumBands() const {return SUBBANDS;} - const matrix_f& getMatrix() {return _Data;} - -protected: - const float* _pSamples; - uint _NumSamples; - uint _NumFrames; - matrix_f _Mi; - matrix_f _Mr; - matrix_f _Data; - -private: - void Init(); -}; - -#endif diff --git a/3rdparty/echoprint-codegen/src/Whitening.cxx b/3rdparty/echoprint-codegen/src/Whitening.cxx deleted file mode 100644 index 55edd3c2b..000000000 --- a/3rdparty/echoprint-codegen/src/Whitening.cxx +++ /dev/null @@ -1,109 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - -#include "Whitening.h" -#include "AudioStreamInput.h" - -Whitening::Whitening(AudioStreamInput* pAudio) { - _pSamples = pAudio->getSamples(); - _NumSamples = pAudio->getNumSamples(); - Init(); -} - -Whitening::Whitening(const float* pSamples, uint numSamples) : - _pSamples(pSamples), _NumSamples(numSamples) { - Init(); -} - -Whitening::~Whitening() { - free(_R); - free(_Xo); - free(_ai); - free(_whitened); -} - -void Whitening::Init() { - int i; - _p = 40; - - _R = (float *)malloc((_p+1)*sizeof(float)); - for (i = 0; i <= _p; ++i) { _R[i] = 0.0; } - _R[0] = 0.001; - - _Xo = (float *)malloc((_p+1)*sizeof(float)); - for (i = 0; i < _p; ++i) { _Xo[i] = 0.0; } - - _ai = (float *)malloc((_p+1)*sizeof(float)); - _whitened = (float*) malloc(sizeof(float)*_NumSamples); -} - -void Whitening::Compute() { - int blocklen = 10000; - int i, newblocklen; - for(i=0;i<(int)_NumSamples;i=i+blocklen) { - if (i+blocklen >= (int)_NumSamples) { - newblocklen = _NumSamples -i - 1; - } else { newblocklen = blocklen; } - ComputeBlock(i, newblocklen); - } -} - -void Whitening::ComputeBlock(int start, int blockSize) { - int i, j; - float alpha, E, ki; - float T = 8; - alpha = 1.0/T; - - // calculate autocorrelation of current block - - for (i = 0; i <= _p; ++i) { - float acc = 0; - for (j = 0; j < (int)blockSize; ++j) { - if (j >= i) { - acc += _pSamples[j+start] * _pSamples[j-i+start]; - } - } - // smoothed update - _R[i] += alpha*(acc - _R[i]); - } - - // calculate new filter coefficients - // Durbin's recursion, per p. 411 of Rabiner & Schafer 1978 - E = _R[0]; - for (i = 1; i <= _p; ++i) { - float sumalphaR = 0; - for (j = 1; j < i; ++j) { - sumalphaR += _ai[j]*_R[i-j]; - } - ki = (_R[i] - sumalphaR)/E; - _ai[i] = ki; - for (j = 1; j <= i/2; ++j) { - float aj = _ai[j]; - float aimj = _ai[i-j]; - _ai[j] = aj - ki*aimj; - _ai[i-j] = aimj - ki*aj; - } - E = (1-ki*ki)*E; - } - // calculate new output - for (i = 0; i < (int)blockSize; ++i) { - float acc = _pSamples[i+start]; - for (j = 1; j <= _p; ++j) { - if (i-j < 0) { - acc -= _ai[j]*_Xo[_p + i-j]; - } else { - acc -= _ai[j]*_pSamples[i-j+start]; - } - } - _whitened[i+start] = acc; - } - // save last few frames of input - for (i = 0; i <= _p; ++i) { - _Xo[i] = _pSamples[blockSize-1-_p+i+start]; - } -} - - diff --git a/3rdparty/echoprint-codegen/src/Whitening.h b/3rdparty/echoprint-codegen/src/Whitening.h deleted file mode 100644 index 146a97216..000000000 --- a/3rdparty/echoprint-codegen/src/Whitening.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - -#ifndef WHITENING_H -#define WHITENING_H -#include "Common.h" -#include "Params.h" -#include "MatrixUtility.h" - - -class AudioStreamInput; - -class Whitening { -public: - inline Whitening() {}; - Whitening(AudioStreamInput* pAudio); - Whitening(const float* pSamples, uint numSamples); - virtual ~Whitening(); - void Compute(); - void ComputeBlock(int start, int blockSize); - -public: - float* getWhitenedSamples() const {return _whitened;} - inline uint getNumSamples() const {return _NumSamples;} - -protected: - const float* _pSamples; - float* _whitened; - uint _NumSamples; - float* _R; - float *_Xo; - float *_ai; - int _p; -private: - void Init(); -}; - -#endif diff --git a/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/README.md b/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/README.md deleted file mode 100644 index 2d5dc2cff..000000000 --- a/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/README.md +++ /dev/null @@ -1,22 +0,0 @@ ------------------------------- -Building echoprint-codegen-ios ------------------------------- - -0. If you don't have it, get [boost](http://www.boost.org/) - **Note:** echoprint-codegen only uses boost headers for some numeric operations, - so you don't need to compile boost. - - -1. Open `echoprint-codegen-ios.xconfig` and set up your boost include directory, e.g., - - HEADER_SEARCH_PATHS = /Users/artgillespie/dev/src/boost_1_46_1 - -2. Build! - -3. If you get a bunch of build errors, goto 2. - -------------------------------------------- -Using echoprint-codegen-ios in your iOS app -------------------------------------------- - -Check out the sample app! diff --git a/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios.xcconfig b/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios.xcconfig deleted file mode 100644 index c2157c624..000000000 --- a/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios.xcconfig +++ /dev/null @@ -1,8 +0,0 @@ -// -// echoprint-codegen-ios.xcconfig -// echoprint-codegen-ios -// -// Created by Art Gillespie on 5/14/11. -// - -HEADER_SEARCH_PATHS = /usr/local/include/boost-1_35 diff --git a/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios.xcodeproj/project.pbxproj b/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios.xcodeproj/project.pbxproj deleted file mode 100644 index f86e75659..000000000 --- a/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios.xcodeproj/project.pbxproj +++ /dev/null @@ -1,302 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 9AAF51A713B2557800099790 /* Whitening.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 9AAF51A513B2557800099790 /* Whitening.cxx */; }; - 9AAF51A813B2557800099790 /* Whitening.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AAF51A613B2557800099790 /* Whitening.h */; }; - 9AE5AA19139FB2620009FCD8 /* SubbandAnalysis.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AE5AA17139FB2620009FCD8 /* SubbandAnalysis.h */; }; - 9AE5AA1A139FB2620009FCD8 /* SubbandAnalysis.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 9AE5AA18139FB2620009FCD8 /* SubbandAnalysis.cxx */; }; - C8D4AD20137EE85F00CD506D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8D4AD1F137EE85F00CD506D /* Foundation.framework */; }; - C8D4AD4F137EF41100CD506D /* AudioBufferInput.cxx in Sources */ = {isa = PBXBuildFile; fileRef = C8D4AD29137EF41100CD506D /* AudioBufferInput.cxx */; }; - C8D4AD50137EF41100CD506D /* AudioBufferInput.h in Headers */ = {isa = PBXBuildFile; fileRef = C8D4AD2A137EF41100CD506D /* AudioBufferInput.h */; }; - C8D4AD51137EF41100CD506D /* AudioStreamInput.cxx in Sources */ = {isa = PBXBuildFile; fileRef = C8D4AD2B137EF41100CD506D /* AudioStreamInput.cxx */; }; - C8D4AD52137EF41100CD506D /* AudioStreamInput.h in Headers */ = {isa = PBXBuildFile; fileRef = C8D4AD2C137EF41100CD506D /* AudioStreamInput.h */; }; - C8D4AD53137EF41100CD506D /* Base64.cxx in Sources */ = {isa = PBXBuildFile; fileRef = C8D4AD2D137EF41100CD506D /* Base64.cxx */; }; - C8D4AD54137EF41100CD506D /* Base64.h in Headers */ = {isa = PBXBuildFile; fileRef = C8D4AD2E137EF41100CD506D /* Base64.h */; }; - C8D4AD55137EF41100CD506D /* Codegen.cxx in Sources */ = {isa = PBXBuildFile; fileRef = C8D4AD2F137EF41100CD506D /* Codegen.cxx */; }; - C8D4AD56137EF41100CD506D /* Codegen.h in Headers */ = {isa = PBXBuildFile; fileRef = C8D4AD30137EF41100CD506D /* Codegen.h */; }; - C8D4AD57137EF41100CD506D /* Common.h in Headers */ = {isa = PBXBuildFile; fileRef = C8D4AD31137EF41100CD506D /* Common.h */; }; - C8D4AD60137EF41100CD506D /* File.h in Headers */ = {isa = PBXBuildFile; fileRef = C8D4AD40137EF41100CD506D /* File.h */; }; - C8D4AD62137EF41100CD506D /* Fingerprint.cxx in Sources */ = {isa = PBXBuildFile; fileRef = C8D4AD42137EF41100CD506D /* Fingerprint.cxx */; }; - C8D4AD63137EF41100CD506D /* Fingerprint.h in Headers */ = {isa = PBXBuildFile; fileRef = C8D4AD43137EF41100CD506D /* Fingerprint.h */; }; - C8D4AD64137EF41100CD506D /* MatrixUtility.cxx in Sources */ = {isa = PBXBuildFile; fileRef = C8D4AD44137EF41100CD506D /* MatrixUtility.cxx */; }; - C8D4AD65137EF41100CD506D /* MatrixUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = C8D4AD45137EF41100CD506D /* MatrixUtility.h */; }; - C8D4AD68137EF41100CD506D /* Params.h in Headers */ = {isa = PBXBuildFile; fileRef = C8D4AD48137EF41100CD506D /* Params.h */; }; - C8D4AD6D137EF41100CD506D /* win_funcs.h in Headers */ = {isa = PBXBuildFile; fileRef = C8D4AD4D137EF41100CD506D /* win_funcs.h */; }; - C8D4AD6E137EF41100CD506D /* win_unistd.h in Headers */ = {isa = PBXBuildFile; fileRef = C8D4AD4E137EF41100CD506D /* win_unistd.h */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 9AAF51A513B2557800099790 /* Whitening.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Whitening.cxx; path = ../Whitening.cxx; sourceTree = SOURCE_ROOT; }; - 9AAF51A613B2557800099790 /* Whitening.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Whitening.h; path = ../Whitening.h; sourceTree = SOURCE_ROOT; }; - 9AE5AA17139FB2620009FCD8 /* SubbandAnalysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SubbandAnalysis.h; path = ../SubbandAnalysis.h; sourceTree = SOURCE_ROOT; }; - 9AE5AA18139FB2620009FCD8 /* SubbandAnalysis.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SubbandAnalysis.cxx; path = ../SubbandAnalysis.cxx; sourceTree = SOURCE_ROOT; }; - C8D4AD1C137EE85F00CD506D /* libechoprint-codegen-ios.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libechoprint-codegen-ios.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - C8D4AD1F137EE85F00CD506D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - C8D4AD23137EE85F00CD506D /* echoprint-codegen-ios-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "echoprint-codegen-ios-Prefix.pch"; sourceTree = ""; }; - C8D4AD29137EF41100CD506D /* AudioBufferInput.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AudioBufferInput.cxx; path = ../../AudioBufferInput.cxx; sourceTree = ""; }; - C8D4AD2A137EF41100CD506D /* AudioBufferInput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioBufferInput.h; path = ../../AudioBufferInput.h; sourceTree = ""; }; - C8D4AD2B137EF41100CD506D /* AudioStreamInput.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AudioStreamInput.cxx; path = ../../AudioStreamInput.cxx; sourceTree = ""; }; - C8D4AD2C137EF41100CD506D /* AudioStreamInput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioStreamInput.h; path = ../../AudioStreamInput.h; sourceTree = ""; }; - C8D4AD2D137EF41100CD506D /* Base64.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Base64.cxx; path = ../../Base64.cxx; sourceTree = ""; }; - C8D4AD2E137EF41100CD506D /* Base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Base64.h; path = ../../Base64.h; sourceTree = ""; }; - C8D4AD2F137EF41100CD506D /* Codegen.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Codegen.cxx; path = ../../Codegen.cxx; sourceTree = ""; }; - C8D4AD30137EF41100CD506D /* Codegen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Codegen.h; path = ../../Codegen.h; sourceTree = ""; }; - C8D4AD31137EF41100CD506D /* Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Common.h; path = ../../Common.h; sourceTree = ""; }; - C8D4AD40137EF41100CD506D /* File.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = File.h; path = ../../File.h; sourceTree = ""; }; - C8D4AD42137EF41100CD506D /* Fingerprint.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Fingerprint.cxx; path = ../../Fingerprint.cxx; sourceTree = ""; }; - C8D4AD43137EF41100CD506D /* Fingerprint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Fingerprint.h; path = ../../Fingerprint.h; sourceTree = ""; }; - C8D4AD44137EF41100CD506D /* MatrixUtility.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MatrixUtility.cxx; path = ../../MatrixUtility.cxx; sourceTree = ""; }; - C8D4AD45137EF41100CD506D /* MatrixUtility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MatrixUtility.h; path = ../../MatrixUtility.h; sourceTree = ""; }; - C8D4AD48137EF41100CD506D /* Params.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Params.h; path = ../../Params.h; sourceTree = ""; }; - C8D4AD4D137EF41100CD506D /* win_funcs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = win_funcs.h; path = ../../win_funcs.h; sourceTree = ""; }; - C8D4AD4E137EF41100CD506D /* win_unistd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = win_unistd.h; path = ../../win_unistd.h; sourceTree = ""; }; - C8D4AD6F137EF5AC00CD506D /* echoprint-codegen-ios.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "echoprint-codegen-ios.xcconfig"; sourceTree = ""; }; - C8D4AD70137EF68F00CD506D /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - C8D4AD19137EE85F00CD506D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - C8D4AD20137EE85F00CD506D /* Foundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - C8D4AD11137EE85F00CD506D = { - isa = PBXGroup; - children = ( - C8D4AD70137EF68F00CD506D /* README.md */, - C8D4AD6F137EF5AC00CD506D /* echoprint-codegen-ios.xcconfig */, - C8D4AD21137EE85F00CD506D /* echoprint-codegen-ios */, - C8D4AD1E137EE85F00CD506D /* Frameworks */, - C8D4AD1D137EE85F00CD506D /* Products */, - ); - sourceTree = ""; - }; - C8D4AD1D137EE85F00CD506D /* Products */ = { - isa = PBXGroup; - children = ( - C8D4AD1C137EE85F00CD506D /* libechoprint-codegen-ios.a */, - ); - name = Products; - sourceTree = ""; - }; - C8D4AD1E137EE85F00CD506D /* Frameworks */ = { - isa = PBXGroup; - children = ( - C8D4AD1F137EE85F00CD506D /* Foundation.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - C8D4AD21137EE85F00CD506D /* echoprint-codegen-ios */ = { - isa = PBXGroup; - children = ( - 9AAF51A513B2557800099790 /* Whitening.cxx */, - 9AAF51A613B2557800099790 /* Whitening.h */, - 9AE5AA17139FB2620009FCD8 /* SubbandAnalysis.h */, - 9AE5AA18139FB2620009FCD8 /* SubbandAnalysis.cxx */, - C8D4AD29137EF41100CD506D /* AudioBufferInput.cxx */, - C8D4AD2A137EF41100CD506D /* AudioBufferInput.h */, - C8D4AD2B137EF41100CD506D /* AudioStreamInput.cxx */, - C8D4AD2C137EF41100CD506D /* AudioStreamInput.h */, - C8D4AD2D137EF41100CD506D /* Base64.cxx */, - C8D4AD2E137EF41100CD506D /* Base64.h */, - C8D4AD2F137EF41100CD506D /* Codegen.cxx */, - C8D4AD30137EF41100CD506D /* Codegen.h */, - C8D4AD31137EF41100CD506D /* Common.h */, - C8D4AD40137EF41100CD506D /* File.h */, - C8D4AD42137EF41100CD506D /* Fingerprint.cxx */, - C8D4AD43137EF41100CD506D /* Fingerprint.h */, - C8D4AD44137EF41100CD506D /* MatrixUtility.cxx */, - C8D4AD45137EF41100CD506D /* MatrixUtility.h */, - C8D4AD48137EF41100CD506D /* Params.h */, - C8D4AD4D137EF41100CD506D /* win_funcs.h */, - C8D4AD4E137EF41100CD506D /* win_unistd.h */, - C8D4AD22137EE85F00CD506D /* Supporting Files */, - ); - path = "echoprint-codegen-ios"; - sourceTree = ""; - }; - C8D4AD22137EE85F00CD506D /* Supporting Files */ = { - isa = PBXGroup; - children = ( - C8D4AD23137EE85F00CD506D /* echoprint-codegen-ios-Prefix.pch */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - C8D4AD1A137EE85F00CD506D /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - C8D4AD50137EF41100CD506D /* AudioBufferInput.h in Headers */, - C8D4AD52137EF41100CD506D /* AudioStreamInput.h in Headers */, - C8D4AD54137EF41100CD506D /* Base64.h in Headers */, - C8D4AD56137EF41100CD506D /* Codegen.h in Headers */, - C8D4AD57137EF41100CD506D /* Common.h in Headers */, - C8D4AD60137EF41100CD506D /* File.h in Headers */, - C8D4AD63137EF41100CD506D /* Fingerprint.h in Headers */, - C8D4AD65137EF41100CD506D /* MatrixUtility.h in Headers */, - C8D4AD68137EF41100CD506D /* Params.h in Headers */, - C8D4AD6D137EF41100CD506D /* win_funcs.h in Headers */, - C8D4AD6E137EF41100CD506D /* win_unistd.h in Headers */, - 9AE5AA19139FB2620009FCD8 /* SubbandAnalysis.h in Headers */, - 9AAF51A813B2557800099790 /* Whitening.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - C8D4AD1B137EE85F00CD506D /* echoprint-codegen-ios */ = { - isa = PBXNativeTarget; - buildConfigurationList = C8D4AD26137EE85F00CD506D /* Build configuration list for PBXNativeTarget "echoprint-codegen-ios" */; - buildPhases = ( - C8D4AD18137EE85F00CD506D /* Sources */, - C8D4AD19137EE85F00CD506D /* Frameworks */, - C8D4AD1A137EE85F00CD506D /* Headers */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "echoprint-codegen-ios"; - productName = "echoprint-codegen-ios"; - productReference = C8D4AD1C137EE85F00CD506D /* libechoprint-codegen-ios.a */; - productType = "com.apple.product-type.library.static"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - C8D4AD13137EE85F00CD506D /* Project object */ = { - isa = PBXProject; - buildConfigurationList = C8D4AD16137EE85F00CD506D /* Build configuration list for PBXProject "echoprint-codegen-ios" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = C8D4AD11137EE85F00CD506D; - productRefGroup = C8D4AD1D137EE85F00CD506D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - C8D4AD1B137EE85F00CD506D /* echoprint-codegen-ios */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - C8D4AD18137EE85F00CD506D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C8D4AD4F137EF41100CD506D /* AudioBufferInput.cxx in Sources */, - C8D4AD51137EF41100CD506D /* AudioStreamInput.cxx in Sources */, - C8D4AD53137EF41100CD506D /* Base64.cxx in Sources */, - C8D4AD55137EF41100CD506D /* Codegen.cxx in Sources */, - C8D4AD62137EF41100CD506D /* Fingerprint.cxx in Sources */, - C8D4AD64137EF41100CD506D /* MatrixUtility.cxx in Sources */, - 9AE5AA1A139FB2620009FCD8 /* SubbandAnalysis.cxx in Sources */, - 9AAF51A713B2557800099790 /* Whitening.cxx in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - C8D4AD24137EE85F00CD506D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = C8D4AD6F137EF5AC00CD506D /* echoprint-codegen-ios.xcconfig */; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = DEBUG; - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_VERSION = com.apple.compilers.llvmgcc42; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; - SDKROOT = iphoneos; - }; - name = Debug; - }; - C8D4AD25137EE85F00CD506D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = C8D4AD6F137EF5AC00CD506D /* echoprint-codegen-ios.xcconfig */; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_VERSION = com.apple.compilers.llvmgcc42; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.2; - SDKROOT = iphoneos; - }; - name = Release; - }; - C8D4AD27137EE85F00CD506D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - DSTROOT = /tmp/echoprint_codegen_ios.dst; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "echoprint-codegen-ios/echoprint-codegen-ios-Prefix.pch"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - C8D4AD28137EE85F00CD506D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - DSTROOT = /tmp/echoprint_codegen_ios.dst; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "echoprint-codegen-ios/echoprint-codegen-ios-Prefix.pch"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - C8D4AD16137EE85F00CD506D /* Build configuration list for PBXProject "echoprint-codegen-ios" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C8D4AD24137EE85F00CD506D /* Debug */, - C8D4AD25137EE85F00CD506D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C8D4AD26137EE85F00CD506D /* Build configuration list for PBXNativeTarget "echoprint-codegen-ios" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C8D4AD27137EE85F00CD506D /* Debug */, - C8D4AD28137EE85F00CD506D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = C8D4AD13137EE85F00CD506D /* Project object */; -} diff --git a/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 4bee8c8f5..000000000 --- a/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios/echoprint-codegen-ios-Prefix.pch b/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios/echoprint-codegen-ios-Prefix.pch deleted file mode 100644 index cd1aae929..000000000 --- a/3rdparty/echoprint-codegen/src/echoprint-codegen-ios/echoprint-codegen-ios/echoprint-codegen-ios-Prefix.pch +++ /dev/null @@ -1,4 +0,0 @@ -// -// Prefix header for all source files of the 'echoprint-codegen-ios' target in the 'echoprint-codegen-ios' project -// - diff --git a/3rdparty/echoprint-codegen/src/main.cxx b/3rdparty/echoprint-codegen/src/main.cxx deleted file mode 100644 index 63a13fbff..000000000 --- a/3rdparty/echoprint-codegen/src/main.cxx +++ /dev/null @@ -1,334 +0,0 @@ -// -// echoprint-codegen -// Copyright 2011 The Echo Nest Corporation. All rights reserved. -// - - -#include -#include -#include -#ifndef _WIN32 - #include - #include -#endif -#include -#include - -#include "AudioStreamInput.h" -#include "Metadata.h" -#include "Codegen.h" -#include -#define MAX_FILES 200000 - -using namespace std; - -// The response from the codegen. Contains all the fields necessary -// to create a json string. -typedef struct { - char *error; - char *filename; - int start_offset; - int duration; - int tag; - double t1; - double t2; - int numSamples; - Codegen* codegen; -} codegen_response_t; - -// Struct to pass to the worker threads -typedef struct { - char *filename; - int start_offset; - int duration; - int tag; - int done; - codegen_response_t *response; -} thread_parm_t; - -// Thank you http://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine -#ifdef _WIN32 -#include -#elif MACOS -#include -#include -#else -#include -#endif - -int getNumCores() { -#ifdef WIN32 - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - return sysinfo.dwNumberOfProcessors; -#elif MACOS - int nm[2]; - size_t len = 4; - uint32_t count; - - nm[0] = CTL_HW; nm[1] = HW_AVAILCPU; - sysctl(nm, 2, &count, &len, NULL, 0); - - if(count < 1) { - nm[1] = HW_NCPU; - sysctl(nm, 2, &count, &len, NULL, 0); - if(count < 1) { count = 1; } - } - return count; -#else - return sysconf(_SC_NPROCESSORS_ONLN); -#endif -} - -// deal with quotes etc in json -std::string escape(const string& value) { - std::string s(value); - std::string out = ""; - out.reserve(s.size()); - for (size_t i = 0; i < s.size(); i++) { - char c = s[i]; - if (c <= 31) - continue; - - switch (c) { - case '"' : out += "\\\""; break; - case '\\': out += "\\\\"; break; - case '\b': out += "\\b" ; break; - case '\f': out += "\\f" ; break; - case '\n': out += "\\n" ; break; - case '\r': out += "\\r" ; break; - case '\t': out += "\\t" ; break; - // case '/' : out += "\\/" ; break; // Unnecessary? - default: - out += c; - // TODO: do something with unicode? - } - } - - return out; -} - -codegen_response_t *codegen_file(char* filename, int start_offset, int duration, int tag) { - // Given a filename, perform a codegen on it and get the response - // This is called by a thread - double t1 = now(); - codegen_response_t *response = (codegen_response_t *)malloc(sizeof(codegen_response_t)); - response->error = NULL; - - auto_ptr pAudio(new FfmpegStreamInput()); - pAudio->ProcessFile(filename, start_offset, duration); - - if (pAudio.get() == NULL) { // Unable to decode! - char* output = (char*) malloc(16384); - sprintf(output,"{\"error\":\"could not create decoder\", \"tag\":%d, \"metadata\":{\"filename\":\"%s\"}}", - tag, - escape(filename).c_str()); - response->error = output; - return response; - } - - int numSamples = pAudio->getNumSamples(); - - if (numSamples < 1) { - char* output = (char*) malloc(16384); - sprintf(output,"{\"error\":\"could not decode\", \"tag\":%d, \"metadata\":{\"filename\":\"%s\"}}", - tag, - escape(filename).c_str()); - response->error = output; - return response; - } - t1 = now() - t1; - - double t2 = now(); - Codegen *pCodegen = new Codegen(pAudio->getSamples(), numSamples, start_offset); - t2 = now() - t2; - - response->t1 = t1; - response->t2 = t2; - response->numSamples = numSamples; - response->codegen = pCodegen; - response->start_offset = start_offset; - response->duration = duration; - response->tag = tag; - response->filename = filename; - - return response; -} - - -void *threaded_codegen_file(void *parm) { - // pthread stub to invoke json_string_for_file - thread_parm_t *p = (thread_parm_t *)parm; - codegen_response_t *response = codegen_file(p->filename, p->start_offset, p->duration, p->tag); - p->response = response; - // mark when we're done so the controlling thread can move on. - p->done = 1; - return NULL; -} - -void print_json_to_screen(char* output, int count, int done) { - // Print a json block depending on how many there are and where we are. - if(done==1 && count>1) printf("[\n%s,\n", output); - else if(done==1 && count == 1) printf("[\n%s\n]\n", output); - else if(done == count) printf("%s\n]\n", output); - else printf("%s,\n", output); -} - -char *make_json_string(codegen_response_t* response) { - - if (response->error != NULL) { - return response->error; - } - - // Get the ID3 tag information. - auto_ptr pMetadata(new Metadata(response->filename)); - - // preamble + codelen - char* output = (char*) malloc(sizeof(char)*(16384 + strlen(response->codegen->getCodeString().c_str()) )); - - sprintf(output,"{\"metadata\":{\"artist\":\"%s\", \"release\":\"%s\", \"title\":\"%s\", \"genre\":\"%s\", \"bitrate\":%d," - "\"sample_rate\":%d, \"duration\":%d, \"filename\":\"%s\", \"samples_decoded\":%d, \"given_duration\":%d," - " \"start_offset\":%d, \"version\":%2.2f, \"codegen_time\":%2.6f, \"decode_time\":%2.6f}, \"code_count\":%d," - " \"code\":\"%s\", \"tag\":%d}", - escape(pMetadata->Artist()).c_str(), - escape(pMetadata->Album()).c_str(), - escape(pMetadata->Title()).c_str(), - escape(pMetadata->Genre()).c_str(), - pMetadata->Bitrate(), - pMetadata->SampleRate(), - pMetadata->Seconds(), - escape(response->filename).c_str(), - response->numSamples, - response->duration, - response->start_offset, - response->codegen->getVersion(), - response->t2, - response->t1, - response->codegen->getNumCodes(), - response->codegen->getCodeString().c_str(), - response->tag - ); - return output; -} - -int main(int argc, char** argv) { - if (argc < 2) { - fprintf(stderr, "Usage: %s [ filename | -s ] [seconds_start] [seconds_duration] [< file_list (if -s is set)]\n", argv[0]); - exit(-1); - } - - try { - string files[MAX_FILES]; - char *filename = argv[1]; - int count = 0; - int start_offset = 0; - int duration = 0; - int already = 0; - if (argc > 2) start_offset = atoi(argv[2]); - if (argc > 3) duration = atoi(argv[3]); - if (argc > 4) already = atoi(argv[4]); - // If you give it -s, it means to read in a list of files from stdin. - if (strcmp(filename, "-s") == 0) { - while(cin) { - if (count < MAX_FILES) { - string temp_str; - getline(cin, temp_str); - if (temp_str.size() > 2) - files[count++] = temp_str; - } else { - throw std::runtime_error("Too many files on stdin to process\n"); - } - } - } else files[count++] = filename; - - if(count == 0) throw std::runtime_error("No files given.\n"); - - -#ifdef _WIN32 - fprintf(stderr, "no thread mode\n"); - // Threading doesn't work in windows yet. - for(int i=0;i 8) num_threads = 8; - if (num_threads < 2) num_threads = 2; - if (num_threads > count) num_threads = count; - - // Setup threading - pthread_t *t = (pthread_t*)malloc(sizeof(pthread_t)*num_threads); - thread_parm_t **parm = (thread_parm_t**)malloc(sizeof(thread_parm_t*)*num_threads); - pthread_attr_t *attr = (pthread_attr_t*)malloc(sizeof(pthread_attr_t)*num_threads); - - // Kick off the first N threads - int still_left = count-1-already; - for(int i=0;ifilename = (char*)files[still_left].c_str(); - parm[i]->start_offset = start_offset; - parm[i]->tag = still_left; - parm[i]->duration = duration; - parm[i]->done = 0; - still_left--; - pthread_attr_init(&attr[i]); - pthread_attr_setdetachstate(&attr[i], PTHREAD_CREATE_DETACHED); - // Kick off the thread - if (pthread_create(&t[i], &attr[i], threaded_codegen_file, (void*)parm[i])) - throw std::runtime_error("Problem creating thread\n"); - } - - int done = 0; - // Now wait for the threads to come back, and also kick off new ones - while(donedone) { - parm[i]->done = 0; - done++; - codegen_response_t *response = (codegen_response_t*)parm[i]->response; - char *json = make_json_string(response); - print_json_to_screen(json, count, done); - free(parm[i]->response); - // More to do? Start a new one on this just finished thread - if(still_left >= 0) { - parm[i]->tag = still_left; - parm[i]->filename = (char*)files[still_left].c_str(); - still_left--; - int err= pthread_create(&t[i], &attr[i], threaded_codegen_file, (void*)parm[i]); - if(err) - throw std::runtime_error("Problem creating thread\n"); - - } - } - } - } - - // Clean up threads - for(int i=0;i -#include -#include - -#define ROUND_FUNC(type,suff) inline type round##suff(type x) \ -{ \ - if (x >= 0.0##suff){ \ - type y = floor##suff(x); \ - if (x - y >= 0.5##suff) \ - y += 1.0##suff; \ - return y; \ - }else{ \ - type y = ceil##suff(x); \ - if (y - x >= 0.5##suff) \ - y -= 1.0##suff; \ - return y; \ - } \ -} - -ROUND_FUNC(float,f) -ROUND_FUNC(double,) - - -inline void gettimeofday(struct timeval* t,void* timezone) -{ struct _timeb timebuffer; - _ftime( &timebuffer ); - t->tv_sec=timebuffer.time; - t->tv_usec=1000*timebuffer.millitm; -} - -#endif /* __WIN_FUNCS_H */ diff --git a/3rdparty/echoprint-codegen/src/win_unistd.h b/3rdparty/echoprint-codegen/src/win_unistd.h deleted file mode 100644 index 7e8bef2d2..000000000 --- a/3rdparty/echoprint-codegen/src/win_unistd.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _UNISTD_H -#define _UNISTD_H 1 - -/* This file intended to serve as a drop-in replacement for - * unistd.h on Windows - * Please add functionality as neeeded - http://stackoverflow.com/questions/341817/is-there-a-replacement-for-unistd-h-for-windows-visual-c - */ - -#include -#include -/* -#include - - getopt from: http://www.pwilson.net/sample.html. */ - -#define srandom srand -#define random rand - -#define F_OK 0 - -#define W_OK 2 -#define R_OK 4 - -#define access _access -#define ftruncate _chsize - -/* stdio */ -#define popen _popen -#define pclose _pclose -/* float.h */ -#define finite _finite - -#define ssize_t int - -#endif /* unistd.h */ - diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b214be2e..297498430 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -360,7 +360,6 @@ add_subdirectory(src) if (WIN32) add_subdirectory(3rdparty/qtwin) endif (WIN32) -add_subdirectory(3rdparty/echoprint-codegen) add_subdirectory(3rdparty/sha2) add_subdirectory(3rdparty/universalchardet) add_subdirectory(tests) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 36aa4ede7..dca77e2ef 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -181,7 +181,6 @@ set(SOURCES library/sqlrow.cpp musicbrainz/chromaprinter.cpp - musicbrainz/echoprinter.cpp musicbrainz/musicbrainzclient.cpp musicbrainz/musicdnsclient.cpp musicbrainz/tagfetcher.cpp @@ -962,7 +961,6 @@ add_dependencies(clementine_lib pot) target_link_libraries(clementine_lib chardet chromaprint_p - echoprint sha2 ${ECHONEST_LIBRARIES} ${GOBJECT_LIBRARIES} diff --git a/src/musicbrainz/echoprinter.cpp b/src/musicbrainz/echoprinter.cpp deleted file mode 100644 index 4363e0dc1..000000000 --- a/src/musicbrainz/echoprinter.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* This file is part of Clementine. - Copyright 2010, David Sansome - - Clementine is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Clementine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Clementine. If not, see . -*/ - -#include "echoprinter.h" -#include "core/logging.h" -#include "core/timeconstants.h" - -#include "3rdparty/echoprint-codegen/src/Codegen.h" - -#include -#include -#include -#include - -Echoprinter::Echoprinter(const QString& filename) - : filename_(filename), - event_loop_(NULL), - convert_element_(NULL), - finishing_(false) -{ - buffer_.open(QIODevice::WriteOnly); -} - -Echoprinter::~Echoprinter() { -} - -GstElement* Echoprinter::CreateElement(const QString &factory_name, - GstElement *bin) { - GstElement* ret = gst_element_factory_make( - factory_name.toAscii().constData(), - factory_name.toAscii().constData()); - - if (ret && bin) - gst_bin_add(GST_BIN(bin), ret); - - if (!ret) { - qLog(Warning) << "Couldn't create the gstreamer element" << factory_name; - } - - return ret; -} - -QString Echoprinter::CreateFingerprint() { - GMainContext* context = g_main_context_new(); - g_main_context_push_thread_default(context); - event_loop_ = g_main_loop_new(context, FALSE); - - pipeline_ = gst_pipeline_new("pipeline"); - GstElement* src = CreateElement("filesrc", pipeline_); - GstElement* decode = CreateElement("decodebin2", pipeline_); - GstElement* convert = CreateElement("audioconvert", pipeline_); - GstElement* resample = CreateElement("audioresample", pipeline_); - GstElement* sink = CreateElement("appsink", pipeline_); - - if (!src || !decode || !convert || !resample || !sink) { - return QString(); - } - - convert_element_ = convert; - - // Connect the elements - gst_element_link_many(src, decode, NULL); - gst_element_link_many(convert, resample, NULL); - - // Echoprint expects mono floats at a sample rate of 11025Hz. - GstCaps* caps = gst_caps_new_simple( - "audio/x-raw-float", - "width", G_TYPE_INT, 32, - "channels", G_TYPE_INT, 1, - "rate", G_TYPE_INT, 11025, - NULL); - gst_element_link_filtered(resample, sink, caps); - gst_caps_unref(caps); - - GstAppSinkCallbacks callbacks; - memset(&callbacks, 0, sizeof(callbacks)); - callbacks.new_buffer = NewBufferCallback; - gst_app_sink_set_callbacks(reinterpret_cast(sink), &callbacks, this, NULL); - g_object_set(G_OBJECT(sink), "sync", FALSE, NULL); - g_object_set(G_OBJECT(sink), "emit-signals", TRUE, NULL); - - // Set the filename - g_object_set(src, "location", filename_.toLocal8Bit().constData(), NULL); - - // Connect signals - g_signal_connect(decode, "new-decoded-pad", G_CALLBACK(NewPadCallback), this); - gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallbackSync, this); - guint bus_callback_id = gst_bus_add_watch(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallback, this); - - QTime time; - time.start(); - - // Start playing - gst_element_set_state(pipeline_, GST_STATE_PLAYING); - - g_main_loop_run(event_loop_); - g_main_loop_unref(event_loop_); - g_main_context_unref(context); - - int decode_time = time.restart(); - - buffer_.close(); - QByteArray data = buffer_.data(); - Codegen codegen(reinterpret_cast(data.constData()), - data.size() / sizeof(float), 0); - QString fingerprint = QString::fromAscii(codegen.getCodeString().c_str()); - int codegen_time = time.elapsed(); - - qLog(Debug) << "Decode time:" << decode_time << "Codegen time:" << codegen_time; - - qLog(Debug) << "Echoprint:" << fingerprint; - - // Cleanup - gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), NULL, NULL); - g_source_remove(bus_callback_id); - gst_object_unref(pipeline_); - - return fingerprint; -} - -void Echoprinter::NewPadCallback(GstElement*, GstPad* pad, gboolean, gpointer data) { - Echoprinter* instance = reinterpret_cast(data); - GstPad* const audiopad = gst_element_get_pad(instance->convert_element_, "sink"); - - if (GST_PAD_IS_LINKED(audiopad)) { - qLog(Warning) << "audiopad is already linked, unlinking old pad"; - gst_pad_unlink(audiopad, GST_PAD_PEER(audiopad)); - } - - gst_pad_link(pad, audiopad); - gst_object_unref(audiopad); -} - -void Echoprinter::ReportError(GstMessage* msg) { - GError* error; - gchar* debugs; - - gst_message_parse_error(msg, &error, &debugs); - QString message = QString::fromLocal8Bit(error->message); - - g_error_free(error); - free(debugs); - - qLog(Error) << "Error processing" << filename_ << ":" << message; -} - -gboolean Echoprinter::BusCallback(GstBus*, GstMessage* msg, gpointer data) { - Echoprinter* instance = reinterpret_cast(data); - - switch (GST_MESSAGE_TYPE(msg)) { - case GST_MESSAGE_ERROR: - instance->ReportError(msg); - g_main_loop_quit(instance->event_loop_); - break; - - default: - break; - } - return GST_BUS_DROP; -} - -GstBusSyncReply Echoprinter::BusCallbackSync(GstBus*, GstMessage* msg, gpointer data) { - Echoprinter* instance = reinterpret_cast(data); - - switch (GST_MESSAGE_TYPE(msg)) { - case GST_MESSAGE_EOS: - g_main_loop_quit(instance->event_loop_); - break; - - case GST_MESSAGE_ERROR: - instance->ReportError(msg); - g_main_loop_quit(instance->event_loop_); - break; - - default: - break; - } - return GST_BUS_PASS; -} - -GstFlowReturn Echoprinter::NewBufferCallback(GstAppSink* app_sink, gpointer self) { - Echoprinter* me = reinterpret_cast(self); - if (me->finishing_) { - return GST_FLOW_OK; - } - - GstBuffer* buffer = gst_app_sink_pull_buffer(app_sink); - me->buffer_.write(reinterpret_cast(buffer->data), buffer->size); - gst_buffer_unref(buffer); - - gint64 pos = 0; - GstFormat format = GST_FORMAT_TIME; - gboolean ret = gst_element_query_position(me->pipeline_, &format, &pos); - if (ret && pos > 30 * kNsecPerSec) { - me->finishing_ = true; - g_main_loop_quit(me->event_loop_); - } - return GST_FLOW_OK; -} diff --git a/src/musicbrainz/echoprinter.h b/src/musicbrainz/echoprinter.h deleted file mode 100644 index 837dce195..000000000 --- a/src/musicbrainz/echoprinter.h +++ /dev/null @@ -1,68 +0,0 @@ -/* This file is part of Clementine. - Copyright 2010, David Sansome - - Clementine is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Clementine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Clementine. If not, see . -*/ - -#ifndef ECHOPRINTER_H -#define ECHOPRINTER_H - -#include -#include -#include - -#include -#include - -class QEventLoop; - -class Echoprinter { - // Creates an Echoprint fingerprint from a song. - // Uses GStreamer to open and decode the file as PCM data and passes this - // to Echoprint's code generator. The generated code can be used to identify - // a song via Echonest's identify method. - // You should create one Echoprinter for each file you want to fingerprint. - // This class works well with QtConcurrentMap. - -public: - Echoprinter(const QString& filename); - ~Echoprinter(); - - // Creates a fingerprint from the song. This method is blocking, so you want - // to call it in another thread. Returns an empty string if no fingerprint - // could be created. - QString CreateFingerprint(); - -private: - GstElement* CreateElement(const QString& factory_name, GstElement* bin = NULL); - - void ReportError(GstMessage* message); - - static void NewPadCallback(GstElement*, GstPad* pad, gboolean, gpointer data); - static gboolean BusCallback(GstBus*, GstMessage* msg, gpointer data); - static GstBusSyncReply BusCallbackSync(GstBus*, GstMessage* msg, gpointer data); - static GstFlowReturn NewBufferCallback(GstAppSink* app_sink, gpointer self); - -private: - QString filename_; - GMainLoop* event_loop_; - - GstElement* convert_element_; - GstElement* pipeline_; - - QBuffer buffer_; - bool finishing_; -}; - -#endif // ECHOPRINTER_H From 2e98ce65d517063e105acb03d9d7c8c085cab04b Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 6 Jan 2012 16:45:34 +0000 Subject: [PATCH 24/40] Disable callbacks after generating fingerprint. (cherry picked from commit 9bb37fda625de498c240e56ef7b7f09ca693c6f7) --- src/musicbrainz/chromaprinter.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/musicbrainz/chromaprinter.cpp b/src/musicbrainz/chromaprinter.cpp index b040295f4..0be12c82e 100644 --- a/src/musicbrainz/chromaprinter.cpp +++ b/src/musicbrainz/chromaprinter.cpp @@ -143,6 +143,8 @@ QString Chromaprinter::CreateFingerprint() { qLog(Debug) << "Decode time:" << decode_time << "Codegen time:" << codegen_time; // Cleanup + callbacks.new_buffer = NULL; + gst_app_sink_set_callbacks(reinterpret_cast(sink), &callbacks, this, NULL); gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), NULL, NULL); g_source_remove(bus_callback_id); gst_object_unref(pipeline_); From 7eb4ab8453fd1ab0d551c1e3d234315880516e84 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 6 Jan 2012 16:51:27 +0000 Subject: [PATCH 25/40] Rename MusicDNS -> Acoustid. (cherry picked from commit cdb381a85f48f66975162f83dc2c1f2cfe2dd8bf) --- src/CMakeLists.txt | 4 ++-- ...{musicdnsclient.cpp => acoustidclient.cpp} | 20 +++++++++---------- .../{musicdnsclient.h => acoustidclient.h} | 14 ++++++------- src/musicbrainz/tagfetcher.cpp | 10 +++++----- src/musicbrainz/tagfetcher.h | 6 +++--- 5 files changed, 27 insertions(+), 27 deletions(-) rename src/musicbrainz/{musicdnsclient.cpp => acoustidclient.cpp} (86%) rename src/musicbrainz/{musicdnsclient.h => acoustidclient.h} (87%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dca77e2ef..70b89ae04 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -180,9 +180,9 @@ set(SOURCES library/librarywatcher.cpp library/sqlrow.cpp + musicbrainz/acoustidclient.cpp musicbrainz/chromaprinter.cpp musicbrainz/musicbrainzclient.cpp - musicbrainz/musicdnsclient.cpp musicbrainz/tagfetcher.cpp playlist/dynamicplaylistcontrols.cpp @@ -417,8 +417,8 @@ set(HEADERS library/libraryviewcontainer.h library/librarywatcher.h + musicbrainz/acoustidclient.h musicbrainz/musicbrainzclient.h - musicbrainz/musicdnsclient.h musicbrainz/tagfetcher.h playlist/dynamicplaylistcontrols.h diff --git a/src/musicbrainz/musicdnsclient.cpp b/src/musicbrainz/acoustidclient.cpp similarity index 86% rename from src/musicbrainz/musicdnsclient.cpp rename to src/musicbrainz/acoustidclient.cpp index c09b773d1..bd9025979 100644 --- a/src/musicbrainz/musicdnsclient.cpp +++ b/src/musicbrainz/acoustidclient.cpp @@ -15,7 +15,7 @@ along with Clementine. If not, see . */ -#include "musicdnsclient.h" +#include "acoustidclient.h" #include #include @@ -26,22 +26,22 @@ #include "core/network.h" #include "core/timeconstants.h" -const char* MusicDnsClient::kClientId = "qsZGpeLx"; -const char* MusicDnsClient::kUrl = "http://api.acoustid.org/v2/lookup"; -const int MusicDnsClient::kDefaultTimeout = 5000; // msec +const char* AcoustidClient::kClientId = "qsZGpeLx"; +const char* AcoustidClient::kUrl = "http://api.acoustid.org/v2/lookup"; +const int AcoustidClient::kDefaultTimeout = 5000; // msec -MusicDnsClient::MusicDnsClient(QObject* parent) +AcoustidClient::AcoustidClient(QObject* parent) : QObject(parent), network_(new NetworkAccessManager(this)), timeouts_(new NetworkTimeouts(kDefaultTimeout, this)) { } -void MusicDnsClient::SetTimeout(int msec) { +void AcoustidClient::SetTimeout(int msec) { timeouts_->SetTimeout(msec); } -void MusicDnsClient::Start(int id, const QString& fingerprint, int duration_msec) { +void AcoustidClient::Start(int id, const QString& fingerprint, int duration_msec) { typedef QPair Param; QList parameters; @@ -62,18 +62,18 @@ void MusicDnsClient::Start(int id, const QString& fingerprint, int duration_msec timeouts_->AddReply(reply); } -void MusicDnsClient::Cancel(int id) { +void AcoustidClient::Cancel(int id) { QNetworkReply* reply = requests_.key(id); requests_.remove(reply); delete reply; } -void MusicDnsClient::CancelAll() { +void AcoustidClient::CancelAll() { qDeleteAll(requests_.keys()); requests_.clear(); } -void MusicDnsClient::RequestFinished() { +void AcoustidClient::RequestFinished() { QNetworkReply* reply = qobject_cast(sender()); if (!reply) return; diff --git a/src/musicbrainz/musicdnsclient.h b/src/musicbrainz/acoustidclient.h similarity index 87% rename from src/musicbrainz/musicdnsclient.h rename to src/musicbrainz/acoustidclient.h index 0d92db9c9..66c1eb6f8 100644 --- a/src/musicbrainz/musicdnsclient.h +++ b/src/musicbrainz/acoustidclient.h @@ -15,8 +15,8 @@ along with Clementine. If not, see . */ -#ifndef MUSICDNSCLIENT_H -#define MUSICDNSCLIENT_H +#ifndef ACOUSTIDCLIENT_H +#define ACOUSTIDCLIENT_H #include #include @@ -26,19 +26,19 @@ class NetworkTimeouts; class QNetworkAccessManager; class QNetworkReply; -class MusicDnsClient : public QObject { +class AcoustidClient : public QObject { Q_OBJECT // Gets a MBID from a Chromaprint fingerprint. // A fingerprint identifies one particular encoding of a song and is created // by Fingerprinter. An MBID identifies the actual song and can be passed to // Musicbrainz to get metadata. - // You can create one MusicDnsClient and make multiple requests using it. + // You can create one AcoustidClient and make multiple requests using it. // IDs are provided by the caller when a request is started and included in - // the Finished signal - they have no meaning to MusicDnsClient. + // the Finished signal - they have no meaning to AcoustidClient. public: - MusicDnsClient(QObject* parent = 0); + AcoustidClient(QObject* parent = 0); // Network requests will be aborted after this interval. void SetTimeout(int msec); @@ -71,4 +71,4 @@ private: QMap requests_; }; -#endif // MUSICDNSCLIENT_H +#endif // ACOUSTIDCLIENT_H diff --git a/src/musicbrainz/tagfetcher.cpp b/src/musicbrainz/tagfetcher.cpp index a87d2b398..8d3a3506a 100644 --- a/src/musicbrainz/tagfetcher.cpp +++ b/src/musicbrainz/tagfetcher.cpp @@ -17,9 +17,9 @@ #include "tagfetcher.h" +#include "acoustidclient.h" #include "chromaprinter.h" #include "musicbrainzclient.h" -#include "musicdnsclient.h" #include "core/timeconstants.h" #include @@ -30,10 +30,10 @@ TagFetcher::TagFetcher(QObject* parent) : QObject(parent), fingerprint_watcher_(NULL), - musicdns_client_(new MusicDnsClient(this)), + acoustid_client_(new AcoustidClient(this)), musicbrainz_client_(new MusicBrainzClient(this)) { - connect(musicdns_client_, SIGNAL(Finished(int,QString)), SLOT(PuidFound(int,QString))); + connect(acoustid_client_, SIGNAL(Finished(int,QString)), SLOT(PuidFound(int,QString))); connect(musicbrainz_client_, SIGNAL(Finished(int,MusicBrainzClient::ResultList)), SLOT(TagsFetched(int,MusicBrainzClient::ResultList))); } @@ -64,7 +64,7 @@ void TagFetcher::Cancel() { fingerprint_watcher_ = NULL; } - musicdns_client_->CancelAll(); + acoustid_client_->CancelAll(); musicbrainz_client_->CancelAll(); songs_.clear(); } @@ -84,7 +84,7 @@ void TagFetcher::FingerprintFound(int index) { } emit Progress(song, tr("Identifying song")); - musicdns_client_->Start(index, fingerprint, song.length_nanosec() / kNsecPerMsec); + acoustid_client_->Start(index, fingerprint, song.length_nanosec() / kNsecPerMsec); } void TagFetcher::PuidFound(int index, const QString& puid) { diff --git a/src/musicbrainz/tagfetcher.h b/src/musicbrainz/tagfetcher.h index 528c7793e..468624a35 100644 --- a/src/musicbrainz/tagfetcher.h +++ b/src/musicbrainz/tagfetcher.h @@ -24,12 +24,12 @@ #include #include -class MusicDnsClient; +class AcoustidClient; class TagFetcher : public QObject { Q_OBJECT - // High level interface to Fingerprinter, MusicDnsClient and + // High level interface to Fingerprinter, AcoustidClient and // MusicBrainzClient. public: @@ -54,7 +54,7 @@ private: static QString GetFingerprint(const Song& song); QFutureWatcher* fingerprint_watcher_; - MusicDnsClient* musicdns_client_; + AcoustidClient* acoustid_client_; MusicBrainzClient* musicbrainz_client_; SongList songs_; From d0eec3f3849db1b3ea76c5fe2880dcfe48736ab5 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 6 Jan 2012 17:01:46 +0000 Subject: [PATCH 26/40] Port Musicbrainz track lookups to API v2. (cherry picked from commit d6bada074a0344f2eafe132d9ceba0e401de39bd) --- src/musicbrainz/musicbrainzclient.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/musicbrainz/musicbrainzclient.cpp b/src/musicbrainz/musicbrainzclient.cpp index e4bf58276..e90879afc 100644 --- a/src/musicbrainz/musicbrainzclient.cpp +++ b/src/musicbrainz/musicbrainzclient.cpp @@ -24,7 +24,7 @@ #include #include -const char* MusicBrainzClient::kTrackUrl = "http://musicbrainz.org/ws/1/track/"; +const char* MusicBrainzClient::kTrackUrl = "http://musicbrainz.org/ws/2/recording/"; const char* MusicBrainzClient::kDiscUrl = "http://musicbrainz.org/ws/1/release/"; const int MusicBrainzClient::kDefaultTimeout = 5000; // msec @@ -39,8 +39,7 @@ void MusicBrainzClient::Start(int id, const QString& mbid) { typedef QPair Param; QList parameters; - parameters << Param("type", "xml") - << Param("inc", "artist+releases"); + parameters << Param("inc", "artists+releases+media"); QUrl url(kTrackUrl + mbid); url.setQueryItems(parameters); @@ -151,7 +150,7 @@ void MusicBrainzClient::RequestFinished() { QXmlStreamReader reader(reply); while (!reader.atEnd()) { - if (reader.readNext() == QXmlStreamReader::StartElement && reader.name() == "track") { + if (reader.readNext() == QXmlStreamReader::StartElement && reader.name() == "recording") { Result track = ParseTrack(&reader); if (!track.title_.isEmpty()) { ret << track; @@ -173,7 +172,7 @@ MusicBrainzClient::Result MusicBrainzClient::ParseTrack(QXmlStreamReader* reader if (name == "title") { ret.title_ = reader->readElementText(); - } else if (name == "duration") { + } else if (name == "length") { ret.duration_msec_ = reader->readElementText().toInt(); } else if (name == "artist") { ParseArtist(reader, &ret.artist_); @@ -182,7 +181,7 @@ MusicBrainzClient::Result MusicBrainzClient::ParseTrack(QXmlStreamReader* reader } } - if (type == QXmlStreamReader::EndElement && reader->name() == "track") { + if (type == QXmlStreamReader::EndElement && reader->name() == "recording") { break; } } From 901463427236b024a5f42a6901d5eb4d34b4dd6c Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 6 Jan 2012 17:08:01 +0000 Subject: [PATCH 27/40] Remove chromaprint shared lib target. (cherry picked from commit 660c68f9d961d987d46633544bb4912503d1648c) --- 3rdparty/chromaprint/src/CMakeLists.txt | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/3rdparty/chromaprint/src/CMakeLists.txt b/3rdparty/chromaprint/src/CMakeLists.txt index cb0afa505..442a0c2fa 100644 --- a/3rdparty/chromaprint/src/CMakeLists.txt +++ b/3rdparty/chromaprint/src/CMakeLists.txt @@ -49,26 +49,3 @@ endif() add_library(chromaprint_p STATIC ${chromaprint_SRCS}) target_link_libraries(chromaprint_p ${chromaprint_LINK_LIBS}) - -set(chromaprint_HDRS chromaprint.h) - -add_library(chromaprint ${chromaprint_SRCS} ${chromaprint_SRCS} ${chromaprint_HDRS}) -set_target_properties(chromaprint PROPERTIES - VERSION ${chromaprint_VERSION} - SOVERSION ${chromaprint_SOVERSION} - PUBLIC_HEADER ${chromaprint_HDRS} - DEFINE_SYMBOL CHROMAPRINT_API_EXPORTS -) -if(BUILD_FRAMEWORK) - set_target_properties(chromaprint PROPERTIES FRAMEWORK TRUE) -endif() -target_link_libraries(chromaprint ${chromaprint_LINK_LIBS}) - -install(TARGETS chromaprint - FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR} - LIBRARY DESTINATION ${LIB_INSTALL_DIR} - RUNTIME DESTINATION ${BIN_INSTALL_DIR} - ARCHIVE DESTINATION ${LIB_INSTALL_DIR} - PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR} -) - From 042ae479f14c6ed5aceb5879a4450a0d929dab4e Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 6 Jan 2012 17:16:01 +0000 Subject: [PATCH 28/40] Reorder DLL deletions. (cherry picked from commit e1804219dc51497b14ea8db168178fbb0df2d0e8) --- dist/windows/clementine.nsi.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dist/windows/clementine.nsi.in b/dist/windows/clementine.nsi.in index 60fbd367d..f3392815c 100644 --- a/dist/windows/clementine.nsi.in +++ b/dist/windows/clementine.nsi.in @@ -87,17 +87,19 @@ Section "Delete old files" oldfiles Delete "$INSTDIR\libgstrtsp-0.10.dll" Delete "$INSTDIR\libgstsdp-0.10.dll" Delete "$INSTDIR\libgsttag-0.10.dll" - Delete "$INSTDIR\libofa.dll" Delete "$INSTDIR\libxml2.dll" Delete "$INSTDIR\z.dll" Delete "$INSTDIR\gstreamer-plugins\libgstasfdemux.dll" Delete "$INSTDIR\gstreamer-plugins\libgstffmpeg-gpl.dll" - Delete "$INSTDIR\gstreamer-plugins\libgstofa.dll" Delete "$INSTDIR\gstreamer-plugins\libgstqueue2.dll" Delete "$INSTDIR\gstreamer-plugins\libgstsoup.dll" ; 1.0 prerelease Delete "$INSTDIR\spotify.dll" + + ; 1.0 + Delete "$INSTDIR\libofa.dll" + Delete "$INSTDIR\gstreamer-plugins\libgstofa.dll" SectionEnd Section "Clementine" Clementine From da2275cd3f1185352af3de9ada757fd3629bceda Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sat, 7 Jan 2012 15:12:26 +0000 Subject: [PATCH 29/40] Remove unused bits from 3rdparty/chromaprint (cherry picked from commit 665b721236e19d1241e395af212e2051739c84dc) --- 3rdparty/chromaprint/CHANGES.txt | 5 - 3rdparty/chromaprint/CMakeLists.txt | 48 --- 3rdparty/chromaprint/NEWS.txt | 44 -- 3rdparty/chromaprint/README.txt | 96 ----- 3rdparty/chromaprint/examples/CMakeLists.txt | 39 -- .../examples/ffmpeg/audioconvert.h | 118 ------ .../chromaprint/examples/ffmpeg/samplefmt.h | 156 ------- 3rdparty/chromaprint/examples/fpcalc.c | 303 -------------- 3rdparty/chromaprint/libchromaprint.pc.cmake | 12 - 3rdparty/chromaprint/tests/CMakeLists.txt | 41 -- 3rdparty/chromaprint/tests/audio_buffer.h | 21 - .../tests/data/test_mono_11025.raw | Bin 44080 -> 0 bytes .../tests/data/test_mono_44100.raw | Bin 176400 -> 0 bytes .../chromaprint/tests/data/test_mono_8000.raw | Bin 31982 -> 0 bytes .../tests/data/test_stereo_44100.raw | Bin 352800 -> 0 bytes 3rdparty/chromaprint/tests/main.cpp | 8 - 3rdparty/chromaprint/tests/test_api.cpp | 99 ----- .../tests/test_audio_processor.cpp | 114 ----- 3rdparty/chromaprint/tests/test_base64.cpp | 56 --- .../tests/test_bit_string_reader.cpp | 47 --- .../tests/test_bit_string_writer.cpp | 53 --- 3rdparty/chromaprint/tests/test_chroma.cpp | 125 ------ .../chromaprint/tests/test_chroma_filter.cpp | 74 ---- .../tests/test_chroma_resampler.cpp | 48 --- .../chromaprint/tests/test_chromaprint.cpp | 67 --- .../tests/test_combined_buffer.cpp | 95 ----- 3rdparty/chromaprint/tests/test_filter.cpp | 25 -- .../chromaprint/tests/test_filter_utils.cpp | 118 ------ .../tests/test_fingerprint_calculator.cpp | 53 --- .../tests/test_fingerprint_compressor.cpp | 79 ---- .../tests/test_fingerprint_decompressor.cpp | 77 ---- .../chromaprint/tests/test_integral_image.cpp | 40 -- 3rdparty/chromaprint/tests/test_lloyds.cpp | 80 ---- 3rdparty/chromaprint/tests/test_quantizer.cpp | 17 - .../tests/test_silence_remover.cpp | 49 --- 3rdparty/chromaprint/tests/test_utils.cpp | 91 ---- 3rdparty/chromaprint/tests/test_utils.h | 42 -- 3rdparty/chromaprint/tools/CMakeLists.txt | 63 --- 3rdparty/chromaprint/tools/chromagram.cpp | 65 --- 3rdparty/chromaprint/tools/decode.cpp | 28 -- 3rdparty/chromaprint/tools/fillpuid.py | 76 ---- 3rdparty/chromaprint/tools/fpcollect.cpp | 323 -------------- 3rdparty/chromaprint/tools/fpeval.cpp | 142 ------- 3rdparty/chromaprint/tools/fpsubmit.py | 121 ------ 3rdparty/chromaprint/tools/learn_filters.cpp | 396 ------------------ 3rdparty/chromaprint/tools/match.h | 42 -- .../chromaprint/tools/misc/prepare-128mp3.sh | 13 - .../chromaprint/tools/misc/prepare-32mp3.sh | 13 - .../chromaprint/tools/misc/prepare-64mp3.sh | 13 - .../chromaprint/tools/misc/prepare-64wma.sh | 13 - .../chromaprint/tools/misc/prepare-gain.sh | 17 - .../tools/misc/prepare-resample.sh | 15 - .../chromaprint/tools/misc/prepare-wav.sh | 9 - 3rdparty/chromaprint/tools/misc/prepare.sh | 9 - 3rdparty/chromaprint/tools/resample.cpp | 35 -- 3rdparty/chromaprint/tools/spectrogram.cpp | 63 --- 56 files changed, 3796 deletions(-) delete mode 100644 3rdparty/chromaprint/CHANGES.txt delete mode 100644 3rdparty/chromaprint/NEWS.txt delete mode 100644 3rdparty/chromaprint/README.txt delete mode 100644 3rdparty/chromaprint/examples/CMakeLists.txt delete mode 100644 3rdparty/chromaprint/examples/ffmpeg/audioconvert.h delete mode 100644 3rdparty/chromaprint/examples/ffmpeg/samplefmt.h delete mode 100644 3rdparty/chromaprint/examples/fpcalc.c delete mode 100644 3rdparty/chromaprint/libchromaprint.pc.cmake delete mode 100644 3rdparty/chromaprint/tests/CMakeLists.txt delete mode 100644 3rdparty/chromaprint/tests/audio_buffer.h delete mode 100644 3rdparty/chromaprint/tests/data/test_mono_11025.raw delete mode 100644 3rdparty/chromaprint/tests/data/test_mono_44100.raw delete mode 100644 3rdparty/chromaprint/tests/data/test_mono_8000.raw delete mode 100644 3rdparty/chromaprint/tests/data/test_stereo_44100.raw delete mode 100644 3rdparty/chromaprint/tests/main.cpp delete mode 100644 3rdparty/chromaprint/tests/test_api.cpp delete mode 100644 3rdparty/chromaprint/tests/test_audio_processor.cpp delete mode 100644 3rdparty/chromaprint/tests/test_base64.cpp delete mode 100644 3rdparty/chromaprint/tests/test_bit_string_reader.cpp delete mode 100644 3rdparty/chromaprint/tests/test_bit_string_writer.cpp delete mode 100644 3rdparty/chromaprint/tests/test_chroma.cpp delete mode 100644 3rdparty/chromaprint/tests/test_chroma_filter.cpp delete mode 100644 3rdparty/chromaprint/tests/test_chroma_resampler.cpp delete mode 100644 3rdparty/chromaprint/tests/test_chromaprint.cpp delete mode 100644 3rdparty/chromaprint/tests/test_combined_buffer.cpp delete mode 100644 3rdparty/chromaprint/tests/test_filter.cpp delete mode 100644 3rdparty/chromaprint/tests/test_filter_utils.cpp delete mode 100644 3rdparty/chromaprint/tests/test_fingerprint_calculator.cpp delete mode 100644 3rdparty/chromaprint/tests/test_fingerprint_compressor.cpp delete mode 100644 3rdparty/chromaprint/tests/test_fingerprint_decompressor.cpp delete mode 100644 3rdparty/chromaprint/tests/test_integral_image.cpp delete mode 100644 3rdparty/chromaprint/tests/test_lloyds.cpp delete mode 100644 3rdparty/chromaprint/tests/test_quantizer.cpp delete mode 100644 3rdparty/chromaprint/tests/test_silence_remover.cpp delete mode 100644 3rdparty/chromaprint/tests/test_utils.cpp delete mode 100644 3rdparty/chromaprint/tests/test_utils.h delete mode 100644 3rdparty/chromaprint/tools/CMakeLists.txt delete mode 100644 3rdparty/chromaprint/tools/chromagram.cpp delete mode 100644 3rdparty/chromaprint/tools/decode.cpp delete mode 100755 3rdparty/chromaprint/tools/fillpuid.py delete mode 100644 3rdparty/chromaprint/tools/fpcollect.cpp delete mode 100644 3rdparty/chromaprint/tools/fpeval.cpp delete mode 100755 3rdparty/chromaprint/tools/fpsubmit.py delete mode 100644 3rdparty/chromaprint/tools/learn_filters.cpp delete mode 100644 3rdparty/chromaprint/tools/match.h delete mode 100755 3rdparty/chromaprint/tools/misc/prepare-128mp3.sh delete mode 100755 3rdparty/chromaprint/tools/misc/prepare-32mp3.sh delete mode 100755 3rdparty/chromaprint/tools/misc/prepare-64mp3.sh delete mode 100755 3rdparty/chromaprint/tools/misc/prepare-64wma.sh delete mode 100755 3rdparty/chromaprint/tools/misc/prepare-gain.sh delete mode 100755 3rdparty/chromaprint/tools/misc/prepare-resample.sh delete mode 100755 3rdparty/chromaprint/tools/misc/prepare-wav.sh delete mode 100755 3rdparty/chromaprint/tools/misc/prepare.sh delete mode 100644 3rdparty/chromaprint/tools/resample.cpp delete mode 100644 3rdparty/chromaprint/tools/spectrogram.cpp diff --git a/3rdparty/chromaprint/CHANGES.txt b/3rdparty/chromaprint/CHANGES.txt deleted file mode 100644 index 6977b6aee..000000000 --- a/3rdparty/chromaprint/CHANGES.txt +++ /dev/null @@ -1,5 +0,0 @@ -Version 0.1 (2010-10-30) -======================== - -- Initial release. - diff --git a/3rdparty/chromaprint/CMakeLists.txt b/3rdparty/chromaprint/CMakeLists.txt index ddcf7afaa..78a054024 100644 --- a/3rdparty/chromaprint/CMakeLists.txt +++ b/3rdparty/chromaprint/CMakeLists.txt @@ -39,29 +39,10 @@ set(BIN_INSTALL_DIR ${EXEC_INSTALL_PREFIX}/bin CACHE PATH "Installation prefix f set(LIB_INSTALL_DIR ${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX} CACHE PATH "Installation prefix for object code libraries" FORCE) set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include CACHE PATH "Installation prefix for C header files" FORCE) -if(APPLE) - option(BUILD_FRAMEWORK "Build an OS X framework" OFF) - set(FRAMEWORK_INSTALL_DIR "/Library/Frameworks" CACHE STRING "Directory to install frameworks to.") -endif() - -option(BUILD_SHARED_LIBS "Build shared libraries" OFF) -option(BUILD_EXAMPLES "Build the examples" OFF) -option(BUILD_TESTS "Build the test suite" OFF) -option(BUILD_TOOLS "Build standard tools" OFF) -option(BUILD_EXTRA_TOOLS "Build extra tools (only useful for development of this library)" OFF) - if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") endif() -if(CMAKE_COMPILER_IS_GNUCXX AND BUILD_SHARED_LIBS) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") -endif() - -if(NOT BUILD_SHARED_LIBS) - add_definitions(-DCHROMAPRINT_NODLL) -endif() option(WITH_AVFFT "Use FFmpeg for FFT calculations" OFF) option(WITH_FFTW3 "Use FFTW3 for FFT calculations" OFF) @@ -123,36 +104,7 @@ if(WITH_FFTW3) message(STATUS "Using FFTW3 for FFT calculations") endif(WITH_FFTW3) -if(NOT APPLE AND NOT BUILD_FRAMEWORK) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libchromaprint.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libchromaprint.pc) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libchromaprint.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) -endif() - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) add_subdirectory(src) -if(BUILD_TOOLS_EXTRA) - find_package(PNG REQUIRED) -endif(BUILD_TOOLS_EXTRA) - -find_package(Boost COMPONENTS system filesystem) -if(BUILD_TOOLS OR BUILD_TOOLS_EXTRA OR BUILD_EXAMPLES) - find_package(FFmpeg REQUIRED) -endif() - -if(BUILD_EXAMPLES) - add_subdirectory(examples) -endif() - -if(BUILD_TOOLS OR BUILD_TOOLS_EXTRA) - find_package(Taglib REQUIRED) - add_subdirectory(tools) -endif(BUILD_TOOLS OR BUILD_TOOLS_EXTRA) - -if(BUILD_TESTS) - find_package(Threads) - find_package(GTest REQUIRED) - add_subdirectory(tests) -endif(BUILD_TESTS) - diff --git a/3rdparty/chromaprint/NEWS.txt b/3rdparty/chromaprint/NEWS.txt deleted file mode 100644 index 96a12b671..000000000 --- a/3rdparty/chromaprint/NEWS.txt +++ /dev/null @@ -1,44 +0,0 @@ -Version 0.6 -- December 22, 2011 -================================ - - - Support for 24-bit file formats in fpcalc. - - The fpcalc utility now uses 120 seconds of audio data by default. - - Python bindings moved to a separate project (pyacoustid). - -Version 0.5 -- October 6, 2011 -============================== - - - Unicode command line handling in fpcalc. - - Fixed a crash in fpcalc when FFmpeg was not able to identify the codec. - - Added encode_fingerprint to the Python bindings. - -Version 0.4 -- May 14, 2011 -=========================== - - - Support for building a Mac OS X framework. - - Support for building a static library. - - Simple C example (fpcalc) that can be used from external applications for - fingerprint calculations. - -Version 0.3 -- April 26, 2011 -============================= - - - Fixed compilation with MSVC 2010. - - Added support for calculating FFT using the Accelerate framework on - Mac OS X and iOS. - - Added Python bindings. - -Version 0.2 -- January 26, 2011 -=============================== - - - New public functions chromaprint_{encode,decode}_fingerprint to - encoding/decoding raw fingerprints. - - New public function chromaprint_dealloc that should be used for - releasing all memory allocated in Chromaprint functions. - - Extended fpcollect to allow processing files with MBIDs. - -Version 0.1 -- October 30, 2010 -=============================== - - - Initial release - diff --git a/3rdparty/chromaprint/README.txt b/3rdparty/chromaprint/README.txt deleted file mode 100644 index aeac70c15..000000000 --- a/3rdparty/chromaprint/README.txt +++ /dev/null @@ -1,96 +0,0 @@ -Chromaprint -=========== - -Dependencies ------------- - -The library itself only depends on a FFT library, which at the moment can -be either FFmpeg [1] (at least r22291, 0.6 is fine), FFTW3 [2] or if you are -on iOS or OS X, you can use the Accelerate/vDSP framework. See the next -section for details. - -The tools included in the package require FFmpeg (can be older), TagLib [3] -and Boost Filesystem [4]. - -In order to build the test suite, you will need the Google Test library [5]. - -[1] http://www.ffmpeg.org/ -[2] http://www.fftw.org/ -[3] http://developer.kde.org/~wheeler/taglib.html -[4] http://www.boost.org/ -[5] http://code.google.com/p/googletest/ - -Installing ----------- - -The most common way to build Chromaprint is like this: - -$ cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLES=ON . -$ make -$ sudo make install - -This will build Chromaprint as a shared library and also include the fpcalc -utility (which is used by MusicBrainz Picard, for example). - -See below for other options. - -FFT Library ------------ - -Chromaprint can use three FFT libraries, FFmpeg, FFTW3 and vDSP. FFmpeg is -preffered, as it's a little faster for our purposes and it's LGPL-licensed, -so it doesn't impact the license of Chromaprint. The FFT interface was added -only recently though, so it might not be available in Linux distributions yet. -FFTW3 can be used in this case, but this library is released under the GPL -license, which makes also the resulting Chromaprint binary GPL licensed. - -If you run simple `cmake .`, it will try to find both FFmpeg and FFTW3 and -select the first one it finds. If you have new FFmpeg installed in a separate -location, you can let CMake know using the `FFMPEG_ROOT` option: - -$ cmake -DFFMPEG_ROOT=/path/to/local/ffmpeg/install . - -If you have new FFmpeg installed, but for some reason prefer to use FFTW3, you -can use the `WITH_FFTW3` option: - -$ cmake -DWITH_FFTW3=ON . - -There is also a `WITH_AVFFT` option, but the script will select the FFmpeg FFT -automatically if it's available, so it shouldn't be necessary to use it. - -If you are on Mac, you can use the standard Accelerate framework with the vDSP -library. This requires you to install no external libraries. It will use -vDSP by default on OS X (but there still is a `WITH_VDSP` option). - -Unit Tests ----------- - -The test suite can be built and run using the following commands: - -$ cmake -DBUILD_TESTS=ON . -$ make check - -Related Projects ----------------- - - * pyacoustid - https://github.com/sampsyo/pyacoustid - * gst-chromaprint - https://github.com/lalinsky/gst-chromaprint - -Standing on the Shoulder of Giants ----------------------------------- - -I've learned a lot while working on this project, which would not be possible -without having information from past research. I've read many papers, but the -concrete ideas implemented in this library are based on the following papers: - - * Yan Ke, Derek Hoiem, Rahul Sukthankar. Computer Vision for Music - Identification, Proceedings of Computer Vision and Pattern Recognition, - 2005. http://www.cs.cmu.edu/~yke/musicretrieval/ - - * Frank Kurth, Meinard Müller. Efficient Index-Based Audio Matching, 2008. - http://dx.doi.org/10.1109/TASL.2007.911552 - - * Dalwon Jang, Chang D. Yoo, Sunil Lee, Sungwoong Kim, Ton Kalker. - Pairwise Boosted Audio Fingerprint, 2009. - http://dx.doi.org/10.1109/TIFS.2009.2034452 - diff --git a/3rdparty/chromaprint/examples/CMakeLists.txt b/3rdparty/chromaprint/examples/CMakeLists.txt deleted file mode 100644 index 40bf00395..000000000 --- a/3rdparty/chromaprint/examples/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -set(EXTRA_LIBS) -if(APPLE) - set(EXTRA_LIBS ${EXTRA_LIBS} -lz) -endif() -if(UNIX) - set(EXTRA_LIBS ${EXTRA_LIBS} -lpthread) -endif() - -set(CMAKE_REQUIRED_LIBRARIES - ${FFMPEG_LIBAVFORMAT_LIBRARIES} - ${FFMPEG_LIBAVCODEC_LIBRARIES} - ${FFMPEG_LIBAVUTIL_LIBRARIES} - ${EXTRA_LIBS}) -check_function_exists(av_audio_convert HAVE_AV_AUDIO_CONVERT) - -if(HAVE_AV_AUDIO_CONVERT) - add_definitions(-DHAVE_AV_AUDIO_CONVERT) -endif() - -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/../src - ${FFMPEG_LIBAVCODEC_INCLUDE_DIRS} - ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS} - ${FFMPEG_LIBAVUTIL_INCLUDE_DIRS} -) - -add_executable(fpcalc fpcalc.c) - - -target_link_libraries(fpcalc chromaprint - ${FFMPEG_LIBAVFORMAT_LIBRARIES} - ${FFMPEG_LIBAVCODEC_LIBRARIES} - ${FFMPEG_LIBAVUTIL_LIBRARIES} - ${EXTRA_LIBS}) - -install(TARGETS fpcalc - RUNTIME DESTINATION ${BIN_INSTALL_DIR} -) - diff --git a/3rdparty/chromaprint/examples/ffmpeg/audioconvert.h b/3rdparty/chromaprint/examples/ffmpeg/audioconvert.h deleted file mode 100644 index 2b28e2eac..000000000 --- a/3rdparty/chromaprint/examples/ffmpeg/audioconvert.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * audio conversion - * Copyright (c) 2006 Michael Niedermayer - * Copyright (c) 2008 Peter Ross - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVCODEC_AUDIOCONVERT_H -#define AVCODEC_AUDIOCONVERT_H - -/** - * @file - * Audio format conversion routines - */ - - -#include "libavcodec/avcodec.h" -#include "samplefmt.h" - -#if FF_API_OLD_SAMPLE_FMT -/** - * @deprecated Use av_get_sample_fmt_string() instead. - */ -attribute_deprecated -void avcodec_sample_fmt_string(char *buf, int buf_size, int sample_fmt); - -/** - * @deprecated Use av_get_sample_fmt_name() instead. - */ -attribute_deprecated -const char *avcodec_get_sample_fmt_name(int sample_fmt); - -/** - * @deprecated Use av_get_sample_fmt() instead. - */ -attribute_deprecated -enum AVSampleFormat avcodec_get_sample_fmt(const char* name); -#endif - -#if FF_API_OLD_AUDIOCONVERT -/** - * @deprecated Use av_get_channel_layout() instead. - */ -attribute_deprecated -int64_t avcodec_get_channel_layout(const char *name); - -/** - * @deprecated Use av_get_channel_layout_string() instead. - */ -attribute_deprecated -void avcodec_get_channel_layout_string(char *buf, int buf_size, int nb_channels, int64_t channel_layout); - -/** - * @deprecated Use av_get_channel_layout_nb_channels() instead. - */ -attribute_deprecated -int avcodec_channel_layout_num_channels(int64_t channel_layout); -#endif - -/** - * Guess the channel layout - * @param nb_channels - * @param codec_id Codec identifier, or CODEC_ID_NONE if unknown - * @param fmt_name Format name, or NULL if unknown - * @return Channel layout mask - */ -uint64_t avcodec_guess_channel_layout(int nb_channels, enum CodecID codec_id, const char *fmt_name); - -struct AVAudioConvert; -typedef struct AVAudioConvert AVAudioConvert; - -/** - * Create an audio sample format converter context - * @param out_fmt Output sample format - * @param out_channels Number of output channels - * @param in_fmt Input sample format - * @param in_channels Number of input channels - * @param[in] matrix Channel mixing matrix (of dimension in_channel*out_channels). Set to NULL to ignore. - * @param flags See AV_CPU_FLAG_xx - * @return NULL on error - */ -AVAudioConvert *av_audio_convert_alloc(enum AVSampleFormat out_fmt, int out_channels, - enum AVSampleFormat in_fmt, int in_channels, - const float *matrix, int flags); - -/** - * Free audio sample format converter context - */ -void av_audio_convert_free(AVAudioConvert *ctx); - -/** - * Convert between audio sample formats - * @param[in] out array of output buffers for each channel. set to NULL to ignore processing of the given channel. - * @param[in] out_stride distance between consecutive output samples (measured in bytes) - * @param[in] in array of input buffers for each channel - * @param[in] in_stride distance between consecutive input samples (measured in bytes) - * @param len length of audio frame size (measured in samples) - */ -int av_audio_convert(AVAudioConvert *ctx, - void * const out[6], const int out_stride[6], - const void * const in[6], const int in_stride[6], int len); - -#endif /* AVCODEC_AUDIOCONVERT_H */ diff --git a/3rdparty/chromaprint/examples/ffmpeg/samplefmt.h b/3rdparty/chromaprint/examples/ffmpeg/samplefmt.h deleted file mode 100644 index 1d3748130..000000000 --- a/3rdparty/chromaprint/examples/ffmpeg/samplefmt.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVUTIL_SAMPLEFMT_H -#define AVUTIL_SAMPLEFMT_H - -#include "libavutil/avutil.h" - -/** - * all in native-endian format - */ -enum AVSampleFormat { - AV_SAMPLE_FMT_NONE = -1, - AV_SAMPLE_FMT_U8, ///< unsigned 8 bits - AV_SAMPLE_FMT_S16, ///< signed 16 bits - AV_SAMPLE_FMT_S32, ///< signed 32 bits - AV_SAMPLE_FMT_FLT, ///< float - AV_SAMPLE_FMT_DBL, ///< double - - AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar - AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar - AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar - AV_SAMPLE_FMT_FLTP, ///< float, planar - AV_SAMPLE_FMT_DBLP, ///< double, planar - - AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically -}; - -/** - * Return the name of sample_fmt, or NULL if sample_fmt is not - * recognized. - */ -const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt); - -/** - * Return a sample format corresponding to name, or AV_SAMPLE_FMT_NONE - * on error. - */ -enum AVSampleFormat av_get_sample_fmt(const char *name); - -/** - * Return the planar<->packed alternative form of the given sample format, or - * AV_SAMPLE_FMT_NONE on error. If the passed sample_fmt is already in the - * requested planar/packed format, the format returned is the same as the - * input. - */ -enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar); - -/** - * Generate a string corresponding to the sample format with - * sample_fmt, or a header if sample_fmt is negative. - * - * @param buf the buffer where to write the string - * @param buf_size the size of buf - * @param sample_fmt the number of the sample format to print the - * corresponding info string, or a negative value to print the - * corresponding header. - * @return the pointer to the filled buffer or NULL if sample_fmt is - * unknown or in case of other errors - */ -char *av_get_sample_fmt_string(char *buf, int buf_size, enum AVSampleFormat sample_fmt); - -#if FF_API_GET_BITS_PER_SAMPLE_FMT -/** - * @deprecated Use av_get_bytes_per_sample() instead. - */ -attribute_deprecated -int av_get_bits_per_sample_fmt(enum AVSampleFormat sample_fmt); -#endif - -/** - * Return number of bytes per sample. - * - * @param sample_fmt the sample format - * @return number of bytes per sample or zero if unknown for the given - * sample format - */ -int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt); - -/** - * Check if the sample format is planar. - * - * @param sample_fmt the sample format to inspect - * @return 1 if the sample format is planar, 0 if it is interleaved - */ -int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt); - -/** - * Get the required buffer size for the given audio parameters. - * - * @param[out] linesize calculated linesize, may be NULL - * @param nb_channels the number of channels - * @param nb_samples the number of samples in a single channel - * @param sample_fmt the sample format - * @return required buffer size, or negative error code on failure - */ -int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, - enum AVSampleFormat sample_fmt, int align); - -/** - * Fill channel data pointers and linesize for samples with sample - * format sample_fmt. - * - * The pointers array is filled with the pointers to the samples data: - * for planar, set the start point of each channel's data within the buffer, - * for packed, set the start point of the entire buffer only. - * - * The linesize array is filled with the aligned size of each channel's data - * buffer for planar layout, or the aligned size of the buffer for all channels - * for packed layout. - * - * @param[out] audio_data array to be filled with the pointer for each channel - * @param[out] linesize calculated linesize - * @param buf the pointer to a buffer containing the samples - * @param nb_channels the number of channels - * @param nb_samples the number of samples in a single channel - * @param sample_fmt the sample format - * @param align buffer size alignment (1 = no alignment required) - * @return 0 on success or a negative error code on failure - */ -int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, uint8_t *buf, - int nb_channels, int nb_samples, - enum AVSampleFormat sample_fmt, int align); - -/** - * Allocate a samples buffer for nb_samples samples, and fill data pointers and - * linesize accordingly. - * The allocated samples buffer can be freed by using av_freep(&audio_data[0]) - * - * @param[out] audio_data array to be filled with the pointer for each channel - * @param[out] linesize aligned size for audio buffer(s) - * @param nb_channels number of audio channels - * @param nb_samples number of samples per channel - * @param align buffer size alignment (1 = no alignment required) - * @return 0 on success or a negative error code on failure - * @see av_samples_fill_arrays() - */ -int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, - int nb_samples, enum AVSampleFormat sample_fmt, int align); - -#endif /* AVUTIL_SAMPLEFMT_H */ diff --git a/3rdparty/chromaprint/examples/fpcalc.c b/3rdparty/chromaprint/examples/fpcalc.c deleted file mode 100644 index e8bf7d5f8..000000000 --- a/3rdparty/chromaprint/examples/fpcalc.c +++ /dev/null @@ -1,303 +0,0 @@ -#include -#include -#include -#include -#ifdef HAVE_AV_AUDIO_CONVERT -#include "ffmpeg/audioconvert.h" -#include "ffmpeg/samplefmt.h" -#endif -#ifdef _WIN32 -#include -#endif - -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -#define BUFFER_SIZE (AVCODEC_MAX_AUDIO_FRAME_SIZE * 2) - -int decode_audio_file(ChromaprintContext *chromaprint_ctx, int16_t *buffer1, int16_t *buffer2, const char *file_name, int max_length, int *duration) -{ - int i, ok = 0, remaining, length, consumed, buffer_size, codec_ctx_opened = 0; - AVFormatContext *format_ctx = NULL; - AVCodecContext *codec_ctx = NULL; - AVCodec *codec = NULL; - AVStream *stream = NULL; - AVPacket packet, packet_temp; -#ifdef HAVE_AV_AUDIO_CONVERT - AVAudioConvert *convert_ctx = NULL; -#endif - int16_t *buffer; - - if (av_open_input_file(&format_ctx, file_name, NULL, 0, NULL) != 0) { - fprintf(stderr, "ERROR: couldn't open the file\n"); - goto done; - } - - if (av_find_stream_info(format_ctx) < 0) { - fprintf(stderr, "ERROR: couldn't find stream information in the file\n"); - goto done; - } - - for (i = 0; i < format_ctx->nb_streams; i++) { - codec_ctx = format_ctx->streams[i]->codec; -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52, 64, 0) - if (codec_ctx && codec_ctx->codec_type == CODEC_TYPE_AUDIO) { -#else - if (codec_ctx && codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { -#endif - stream = format_ctx->streams[i]; - break; - } - } - if (!stream) { - fprintf(stderr, "ERROR: couldn't find any audio stream in the file\n"); - goto done; - } - - codec = avcodec_find_decoder(codec_ctx->codec_id); - if (!codec) { - fprintf(stderr, "ERROR: unknown codec\n"); - goto done; - } - - if (avcodec_open(codec_ctx, codec) < 0) { - fprintf(stderr, "ERROR: couldn't open the codec\n"); - goto done; - } - codec_ctx_opened = 1; - - if (codec_ctx->channels <= 0) { - fprintf(stderr, "ERROR: no channels found in the audio stream\n"); - goto done; - } - - if (codec_ctx->sample_fmt != SAMPLE_FMT_S16) { -#ifdef HAVE_AV_AUDIO_CONVERT - convert_ctx = av_audio_convert_alloc(SAMPLE_FMT_S16, codec_ctx->channels, - codec_ctx->sample_fmt, codec_ctx->channels, NULL, 0); - if (!convert_ctx) { - fprintf(stderr, "ERROR: couldn't create sample format converter\n"); - goto done; - } -#else - fprintf(stderr, "ERROR: unsupported sample format\n"); - goto done; -#endif - } - - *duration = stream->time_base.num * stream->duration / stream->time_base.den; - - av_init_packet(&packet); - av_init_packet(&packet_temp); - - remaining = max_length * codec_ctx->channels * codec_ctx->sample_rate; - chromaprint_start(chromaprint_ctx, codec_ctx->sample_rate, codec_ctx->channels); - - while (1) { - if (av_read_frame(format_ctx, &packet) < 0) { - break; - } - - packet_temp.data = packet.data; - packet_temp.size = packet.size; - - while (packet_temp.size > 0) { - buffer_size = BUFFER_SIZE; -#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(52, 25, 0) - consumed = avcodec_decode_audio2(codec_ctx, - buffer1, &buffer_size, packet_temp.data, packet_temp.size); -#else - consumed = avcodec_decode_audio3(codec_ctx, - buffer1, &buffer_size, &packet_temp); -#endif - - if (consumed < 0) { - break; - } - - packet_temp.data += consumed; - packet_temp.size -= consumed; - - if (buffer_size <= 0) { - if (buffer_size < 0) { - fprintf(stderr, "WARNING: size returned from avcodec_decode_audioX is too small\n"); - } - continue; - } - if (buffer_size > BUFFER_SIZE) { - fprintf(stderr, "WARNING: size returned from avcodec_decode_audioX is too large\n"); - continue; - } - -#ifdef HAVE_AV_AUDIO_CONVERT - if (convert_ctx) { - const void *ibuf[6] = { buffer1 }; - void *obuf[6] = { buffer2 }; - int istride[6] = { av_get_bits_per_sample_format(codec_ctx->sample_fmt) / 8 }; - int ostride[6] = { 2 }; - int len = buffer_size / istride[0]; - if (av_audio_convert(convert_ctx, obuf, ostride, ibuf, istride, len) < 0) { - break; - } - buffer = buffer2; - buffer_size = len * ostride[0]; - } - else { - buffer = buffer1; - } -#else - buffer = buffer1; -#endif - - length = MIN(remaining, buffer_size / 2); - if (!chromaprint_feed(chromaprint_ctx, buffer, length)) { - fprintf(stderr, "ERROR: fingerprint calculation failed\n"); - goto done; - } - - if (max_length) { - remaining -= length; - if (remaining <= 0) { - goto finish; - } - } - } - - if (packet.data) { - av_free_packet(&packet); - } - } - -finish: - if (!chromaprint_finish(chromaprint_ctx)) { - fprintf(stderr, "ERROR: fingerprint calculation failed\n"); - goto done; - } - - ok = 1; - -done: - if (codec_ctx_opened) { - avcodec_close(codec_ctx); - } - if (format_ctx) { - av_close_input_file(format_ctx); - } -#ifdef HAVE_AV_AUDIO_CONVERT - if (convert_ctx) { - av_audio_convert_free(convert_ctx); - } -#endif - return ok; -} - -int fpcalc_main(int argc, char **argv) -{ - int i, j, max_length = 120, num_file_names = 0, raw = 0, raw_fingerprint_size, duration; - int16_t *buffer1, *buffer2; - int32_t *raw_fingerprint; - char *file_name, *fingerprint, **file_names; - ChromaprintContext *chromaprint_ctx; - - file_names = malloc(argc * sizeof(char *)); - for (i = 1; i < argc; i++) { - char *arg = argv[i]; - if (!strcmp(arg, "-length") && i + 1 < argc) { - max_length = atoi(argv[++i]); - } - else if (!strcmp(arg, "-raw")) { - raw = 1; - } - else { - file_names[num_file_names++] = argv[i]; - } - } - - if (!num_file_names) { - printf("usage: %s [OPTIONS] FILE...\n\n", argv[0]); - printf("Options:\n"); - printf(" -length SECS length of the audio data used for fingerprint calculation (default 120)\n"); - printf(" -raw output the raw uncompressed fingerprint\n"); - return 2; - } - - av_register_all(); - av_log_set_level(AV_LOG_ERROR); - - buffer1 = av_malloc(BUFFER_SIZE + 16); - buffer2 = av_malloc(BUFFER_SIZE + 16); - chromaprint_ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_DEFAULT); - - for (i = 0; i < num_file_names; i++) { - file_name = file_names[i]; - if (!decode_audio_file(chromaprint_ctx, buffer1, buffer2, file_name, max_length, &duration)) { - fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name); - continue; - } - if (i > 0) { - printf("\n"); - } - printf("FILE=%s\n", file_name); - printf("DURATION=%d\n", duration); - if (raw) { - if (!chromaprint_get_raw_fingerprint(chromaprint_ctx, (void **)&raw_fingerprint, &raw_fingerprint_size)) { - fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name); - continue; - } - printf("FINGERPRINT="); - for (j = 0; j < raw_fingerprint_size; j++) { - printf("%d%s", raw_fingerprint[j], j + 1 < raw_fingerprint_size ? "," : "\n"); - } - chromaprint_dealloc(raw_fingerprint); - } - else { - if (!chromaprint_get_fingerprint(chromaprint_ctx, &fingerprint)) { - fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name); - continue; - } - printf("FINGERPRINT=%s\n", fingerprint); - chromaprint_dealloc(fingerprint); - } - } - - chromaprint_free(chromaprint_ctx); - av_free(buffer1); - av_free(buffer2); - free(file_names); - - return 0; -} - -#ifdef _WIN32 -int main(int win32_argc, char **win32_argv) -{ - int i, argc = 0, buffsize = 0, offset = 0; - char **utf8_argv, *utf8_argv_ptr; - wchar_t **argv; - - argv = CommandLineToArgvW(GetCommandLineW(), &argc); - - buffsize = 0; - for (i = 0; i < argc; i++) { - buffsize += WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL); - } - - utf8_argv = av_mallocz(sizeof(char *) * (argc + 1) + buffsize); - utf8_argv_ptr = (char *)utf8_argv + sizeof(char *) * (argc + 1); - - for (i = 0; i < argc; i++) { - utf8_argv[i] = &utf8_argv_ptr[offset]; - offset += WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, &utf8_argv_ptr[offset], buffsize - offset, NULL, NULL); - } - - LocalFree(argv); - - return fpcalc_main(argc, utf8_argv); -} -#else -int main(int argc, char **argv) -{ - return fpcalc_main(argc, argv); -} -#endif - diff --git a/3rdparty/chromaprint/libchromaprint.pc.cmake b/3rdparty/chromaprint/libchromaprint.pc.cmake deleted file mode 100644 index ac94b28da..000000000 --- a/3rdparty/chromaprint/libchromaprint.pc.cmake +++ /dev/null @@ -1,12 +0,0 @@ -prefix=${CMAKE_INSTALL_PREFIX} -exec_prefix=${EXEC_INSTALL_PREFIX} -libdir=${LIB_INSTALL_DIR} -includedir=${INCLUDE_INSTALL_DIR} - -Name: ${PROJECT_NAME} -Description: Audio fingerprint library -URL: http://wiki.acoustid.org/wiki/Chromaprint -Version: ${PROJECT_VERSION} -Libs: -L${LIB_INSTALL_DIR} -lchromaprint -Cflags: -I${INCLUDE_INSTALL_DIR} - diff --git a/3rdparty/chromaprint/tests/CMakeLists.txt b/3rdparty/chromaprint/tests/CMakeLists.txt deleted file mode 100644 index bd4b4066d..000000000 --- a/3rdparty/chromaprint/tests/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -include_directories( - ${GTEST_INCLUDE_DIRS} - ${CMAKE_CURRENT_SOURCE_DIR}/../src -) - -set(tests_SOURCES - main.cpp - test_api.cpp - test_combined_buffer.cpp - test_utils.cpp - test_quantizer.cpp - test_filter_utils.cpp - test_integral_image.cpp - test_lloyds.cpp - test_audio_processor.cpp - test_bit_string_reader.cpp - test_bit_string_writer.cpp - test_chromaprint.cpp - test_chroma.cpp - test_chroma_filter.cpp - test_chroma_resampler.cpp - test_fingerprint_compressor.cpp - test_fingerprint_decompressor.cpp - test_fingerprint_calculator.cpp - test_filter.cpp - test_silence_remover.cpp - test_base64.cpp -) - -add_executable(all_tests ${tests_SOURCES}) -target_link_libraries(all_tests - ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} - chromaprint_p -) - -add_custom_target(check - ./all_tests $ENV{GTEST_FLAGS} - DEPENDS all_tests -) - diff --git a/3rdparty/chromaprint/tests/audio_buffer.h b/3rdparty/chromaprint/tests/audio_buffer.h deleted file mode 100644 index 165879e75..000000000 --- a/3rdparty/chromaprint/tests/audio_buffer.h +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include "audio_consumer.h" - -class AudioBuffer : public Chromaprint::AudioConsumer -{ -public: - void Consume(short *input, int length) - { - //cout << "AudioBuffer::Consume(" << length << ")\n"; - int last_size = m_data.size(); - //cout << "got " << input[0] << " at index " << last_size << "\n"; - m_data.resize(last_size + length); - std::copy(input, input + length, m_data.begin() + last_size); - } - - const std::vector &data() { return m_data; } - -private: - std::vector m_data; -}; diff --git a/3rdparty/chromaprint/tests/data/test_mono_11025.raw b/3rdparty/chromaprint/tests/data/test_mono_11025.raw deleted file mode 100644 index f6fedcd8a92771a6c070577bb3224ad8c63b0356..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44080 zcmeF)iN8tTeSy7>g$WY0Usi=qsgfx(`OeK-1BxFd4LMjwRNu?xY zN-~7Z^St---sk)Jy?%eh^K@S4be!|~-21-Qy4JO>weEZG69oV7zyBL85C&n|vg7#w zUws@$aU6$1N|4S+s#hdGNq+XfS0(?t7GL#|{4B*QlGmje;D4`3N&7zeedy;I{XR&$ z%KtY?;P^!*NG5$`GH6e+;@=_o+C4 z&^mZNm>&EVtP55I`+}pv*TJIT%b=r=Z-bYDf8y2gfM9g+a=b4(72RTlK4$P{{CYey z{ysk8D(QpFK_+XeZVruu&Oz_svEbpLeQ>9_oQp5V*9BYR9dXOxzj$ceHE0&>k3SAB z2djeTyyr@s%j|+6n^8&zRehH+xQ=DZ1$C^eb?~4u3Ix@HLe^L(I2k`0o*@3EJ{(`5-rs z9ptMZm>d5XUy8fMgW^`f()j7Pdhl!9DV`f&j5`Ex1oxVCdE+mQd&hO+YVoD$QgkKS z7G;fF#jnL*^FqepQd~U9&J#U?!|`A7_~1}{Jo$ONIG)9ui{d%)WPa-lLoI>|tUsRR zy0Y@)Q1*B*BpB;sQZPGM>|>?hEePHTo(=j1{eucD_Atw43K|Aa2QPZvx8CW~>Qju`ymAZ#Ba`@mZK(0C#Ks z{zANq-QS9r#0$ND0;}I{7GvY?qG5YHA;=wGcFocv@g`R)#LDO5DnTnNDb7B(vC7A0 zQYq+QPWgf|L1o^`6#T@(&jd^2r-DvFmmphMEVwoPEw0EmW&LDAupZuaS;JUYJSNgM z#$$NAczh(<6wQs6Mq8tQqB8NL<~28dA1jRsmIasjzjM$ejDvBmIhd8VV3)P=hyK4Q z9v8pt`#|h$5`S}od1jU0ydGqoS@E}VPto>sd`CPyem3|X9(o7IS@}73*b=YgtB-KQ ztoRf5|2v-NwV&gaUU5AbdkZ3avRlib4`dG$J6%%ZOiYzz%c8=*#@EC9Z{Q zjKH2Znz;@SvWn#u zJhPjJqBsv9e~C*6W8|{&@#rzv%81!68tJ`wL_8j=zQkIy;$b*yS3C{JRmO&SgImnH z7jGxblpB-(DLyV6vwCoW_de!>K4SBq_&zb&2DYAp_&0plBiJoor-|fYagMkGMrjf^ z3l79zMc+o%ME()%bGs4u#94#AvOu07D|BYF{;KBlW}G)}YV5XfGoOd^1v^;$DxTRD zHHnu;yQ4f}douK|u)9?`E%E8E59Fb~4FSBXtelg`8(t^mW|+7sS3Ld%VnYXZhe7 zycOZ4!{Tj2&@;>%JRYaRHh0P-e+6IQs*CZwph(<3$|tUhvuEb`OjJ5<5s#D;$FOCs zAcIWS1=s9hkzD*1#(zd7g7Nq&OHfd5E@8ee1p_cadKvf@nWP|mH#eKB^7d&SIuA#g zMCvBvWyP#Lg4x!(6w|Mdo8zPE@x`d6I7u&q?GuGrF=<79DiQa<K#_-Xgk=*yb^}iXv z!b(-*e(^)`o#NtcC^*3SXX4VqI=^o(&Yl;8%YzdbVv%)p6K7q6CGy90!P$5}&Y2m1 zisMdDE#)xBucBk7pB~`3JZ4xKLfd2LtMNv8^*OKljo)q)8QEDV9d&TUclB^!FCP_-1SAA72;OmvhI7>UDhZwAlCn=R73NiU!$Tb&`m08efYxMu($6qbYIjpg>#` z=B8l0`qq0D+Q(tb~@`G#Bbt8#Cz_*cC3L$oUD7Qe&KKg3^BK&|-j zzhJv~Ta8^i82J%eGReLNA*3Now)5^6AbX$O(>Qp@l^&3T$A>M$^I~QQFV3NFI`HVm zXsGP^M>IToi$~9UbxXNu5dL`-=1)bZqeA#-wQO1wqI${@wSv0hq<2t7Zp{&V1tp)v zQ^n6EQSm8%P&RD)i;THHen=eVhMejwupZ7ziqc{{w>ZutUe?DaqbFdcK2};9cf+PP z8}&c-n<>Mzi9aycE7aX7Svf@{ABYF1v2bxr@FF&z!IzC?jA4}A2i{R%-X9ACT`_sP z_+(r(tPt#sdxaOnzG0DYuE^LW!<=T{!?Mihv{c8SLC_?a2j%z12crVfQ_*QrRME=6 z!?fALsxskZ{(W2w{bE+{L*!SkyI!=du)?e?T+-E#W426`$R^qSP}~AHO^ctA+m^^J zJ+a`!-d7Ck-YvFQ24Q$5_`zyBThl*mHaC7sP8t=Q{vdCiS{SFp~uzAa{ zH!ahiUkCB@+r0NZZMGx$JYEvrB~wjzy*>D08GJY5yS6NQD#{!G6P1VuvhJFAAy$5u zSIz~^!+hZzc=IxgZN|#KLC1HPt0-(%=G|L)>@sE6T?}ux%FFTOU@o6E4?Y#Oo1o>m zJkiZ>`oxu3?ksMp6MRVb)x!i=G4(dDSYs74=%%IcPzdsCQm3zDodMQ*()>P(*RsYf zSovt25;h2zyXpftBaD|t7schQ=o6a#J@#rO8vc||K9^aV!qV*+q5$NbHj~)A&zt4s zxPMSDtP%_sFJHn)h%x?!zkO!0-wG~^$bGWw2vM|6to4#HJHdZ-(U=K;-zaich^*Cd z1InmK@GP!c!Om5!s0%&S3&+ehaw-dzpo%`n{+rn^mw(+%`wtJc1-ZgnVYTpY%H<`N z-o_&XAf#-3AGJ8267LB|%f0?!TraF0o`#o^R`Cn(y-SDniSx(zh@?UM^$D%hS`2lB z_dFEFW-L)MI40h2hr_+N_D3HVX@%l2RTF>pG&dT<`h_qcs z>SD&D;jEbK^BDgfrJFy*XGx4rlMR-*%46(xRz}|F{S9!`CCa`M{BFhTS;W*fHPyv5 z-aH(ap?LC!7iqhJMyYHiwb`l?&i^`CD3@--zqhhwWfAn7YB^sxnMN7R<{hB#3f}!A zF2*mLDDu0oZBt&Thx;Gqn=`C)6BhoN4IdD7o789t%N&I9yXl;ASmb$3*VX8+s~8U8 z_d{$vRQ&a&fZDl65)FmT>|yhJ4YR(C3${|}N9loFDz!XpSBv-Zo8=^2o5bc3`gyLO zjWa@}_-M3N#@ZL(guy#&Bb0*CKci03yr{J}U1x*|eEJ0K(at=YtHghS#W;SJt!nvN zDQ@evszj0y1z(791f(hXt))yeZJwKFovD|k0!Sc=x!8eH^_hg9;f zc-0w5uSykEa?O~6xtB$E1|Q+|@x0cRHb^=R3o$?ov&$-{&cT{Hp`o;l^?Te?#dlII z*H2E|&ZZARZ+;y1h4uA~=S7v`CopnJnf4|go8Zcot?y@6?50kCQucjC?NwI1KkN#t zMN`+fAcfF9=qo>z!L=hq)0<}hw3?>3*L09wUr~XNw&r5;`Cg2-oJvY6vi7cj5(+*r zyD!xewqDJrL zfxNhM9t3WV?`45cWQ+yW)syi=Sbbi`TBn!OO@8Q)As(bbu3_`K&{SGROvRabt+$6+ zXA)EAg2ymrKlNfqT-;gKX%#oa3}@J^1~2!;^W&_tsoWlk(gSdk9cTQ3&Ca;iavr_` zyEcxmH}Yp{fu`Xl+|-gTOKS2*;#;A=2bAqrE7hWBH&G*h&@~U3K{fTnz;(5yjh)e;@E!Tvkdk z!at&YyZA2?UKg&HF-uP_P5UWms#_AZQkrn>MUi0Ln z;p(=XQJ(ni=vFEntP25lirnvVC)0X zw>w?{#r5g?9YF;>)%W3Os+C22+JL<~L)JaGs1yEbfPLD)#DCs76%O~y6K8zaS^gRj z*Ji&{l;!tux0ywr#ULZaL`j)!y}Wu;Tv*g(lgs+@_(ME2NpIi@*0?IW_Q$9nvFz`9 z2Hn&Mck5*|kM{(n!lCke6L!ofcefGIz0{B|$Z+Y+=MmgE3`6Fymb*-)=MFw*nVIxjd--h-*6VAHHE>uDqt0aWBx--usi{Og z9%Ru8*y#_9SxrQ(wWbBMN+fG`!YiwETW85Gi)q`e;Z5Nw- ze|F6~f|^#iJAMZPy&*zsQ4HteI#72eu4X+I@Ww{0+Zm_Vqjt98l0`;NV!0Au7PR8q zg2(v&wxBlU5M!b{dFpHGqmJnP2j>1XmvhmN(Ra~b(G76_A|^biyL698{?MvwW8fv! zb158l39D_SW>TR42;Ny^T_5mNo4Bdin;K13aXu#>j$z>`c&8MWEeP!!D8@kCmrv_Y zu23D^sn0Mc_%&D?XNc3mZj#rQsAKzzwr_A@B|7GMRxM1wt`c{NPPvb_Zd5PNGKWHN zRZG-l36GiMX}RM+S@xu>Ms(O-3>dRZ6*ijUI>S`+)A^^Fxz!PWi8|k)?raVf6TN1x z`R-SNw&(o|RMvdz|9!Fi5>>xLb>GtZmc^r^sZkyA-;X_)x=K2X)y7KBV(#Nb1cc;%vi-p>3 zvq+4sjT=(boAgX>743~>(KkeG20wpR6va^yb$3J6WG#3d$WD(_|7~QudLpoeSv2=u zOKiJP{&_|&oSRl`qG{Ub-G5%X+2;rRB`<#^Pi>O|5F!KV*4lkc8$ormF2f#ohstI zEM+$jQisdOSK|U<%olMtVu;+U+}x6AG#N> zKLQz>L`7yuI2upWXId0j4gaN;T2V_g)#cfE?!WjJ71BrgR7FKs(&ugm&yUfVH{psB z*s(3I^rSB*Q7`N8V4`H_$nGcYEBwc%SAwrxcNouXpeg^wNV_S}zj@#gy|v1kPg1$l z()xOb^{84<84ri^soVWHXBZZE-;B1%5F;ROI4iVw#meDpVTZ6wSR<_tzeTk(otRhAjW^#m+1i|^~;?x7U? z9OG^A?%P<|FDwWduTpuyF9^}9BT@h8pAkjZ4E*f9u+v{MXJ73I} zowubagu)a-X}A<=R(cMj<@ECbV)Xh&??*86`m+ifyhipaQ+vTh;sHpH`! z$TU^4S$%QYLw?>Oihi`1q5pD`3al*>Q`Uwh>29XQg!_FSnl# z!JE~C-!a*4`KP~{;t`zRSjJo*WrMp5`hTyf+P=cqLwV>w(VJVAT}o%4pu8@#)tgW< zKo)E2YZ>ajDW$M1*o=E~vC=sjtE#=D4zSh4&sR{|AL7RcX_bj$G81-vUgSPRHMGI@ zZ~J@-GM=!jb(ZG)2RA(~N1x^A)pE;mcK=H5t--2A*r<|TdTH#^8-@zVXxHJ!+-Y3% zvD~!6s{2y)Bh9=Wub!u@XN#R&!4ERoOSD@n=sjudt9UMh^{i&=wQ9*g99Nf(V_qs}nDkM9@Rq3caCWrw@^w81oybR&h6 z7Yat|FVr&2hI;-V+q-%a=Y1ib%ZQ@=x^t)4vjB8vq9?zna;EUadJ1g1pX9^%vC9LmQCl&Uwio{n-yGTnf+?SORljRCtswOFRI{*yWVGV zZaYdnVe^C0P+jjzROw;b?FuBktUhw)Ko@KYYqn;Yo;W-~{4i|!H2Zh3-r5-HW;t-Q z2wX2BcC*|h5jzIkBvsT=V}D`pxmYQccem@-oxyOie0R?0&;Gr~tcqAu(z85(eM$sv z&Az3*y^8eBc(MGPzIP=`tALJr!vC?0&Zc)(YdI zo3P6r$v#B1FxnsOiyF!Gv-u_)yf?y-k5IjDTg9FD&MIA;*L=~vf18jp0vHVb)w^OKCiF0{*3DAZ4q7rLzXZ?WtIDO z_`ak|cUycX9X;6`A9JNEa(X%|I1Y&?@J4C2n(oS< zjde#*!#i6#w^PCOp2hPsMexV6;{fxhVi&Eg9Pv8Nt}h~2V&dJbxK-?qlP@OYfx5=p zp>Md)&mN11%A&7Ye+tj-HbPM<@$cxz_%~|19n8EU&kmwDK9yevLfseCT|MmL+jAayq2@7^&>A_}x9;eNb!3)9kXzJ{K`TBdgd9WC7!@l2P=<2+vpG)KC zrD$)`7g*qIOKn$gfWdCS=)dvQD6eiVe{A5#6@IrKGLthjC1I{LyW9b<%~|85^F2vV z`!UsN4!a>+W!;nUATg9fP9CU-nNQznfC#H-mA7G~HSF1&H|nV2UQxZ(mFZqgW5aHk zrK;Nfh->%8|2yI9Q|oDNk7BG>6mb29I#ciS?Q*kdu8MAoAN#`eP&s)A6gI)AWyHu~ z*By^F>(fpv#PmumThqTwK~QPD{Em^b$YXnXa*LQN4&P^Z|DtTWSZ41aqi^6h=la5| z;rg(7cnl6(%SC%cNA{qWlO7LZk{2n4*KzeWABC~_KeWyp{I}H1|K_!~S^f)LR02wi zIz>}nmYU;~MAA>}&TkLd0V<<&@mDlNEtVhC?WKbA>SZo8-+cBK9_Nc0Ue|+fA2#QS zP8!`B48b$`WbkKsrh+;usitNa^(3{{4d1^EITggxaNUVfxO^e|^~QdEVBs^bxEfW% zrgO|TiICIk?FU$Lw>dn=0>1?>#oMFiIICz{v@fy3NSClYKKslGv}H~&9JW(B1=dIK z?Oy9UWK}$Q!%KTWrYbd?h$eK`B_u7R6n_(wULtD?|dr55!Q95n)Z5Uk#55+9j*FS zE2w5G_&iJS3 z)#xeXXB8pusfVAzBmsmju_tiEsksZVvPKoxI7oVh51V72cvUnz+N`%yL|0ivimUZ> z#suCgip!hGyBF!m&blrOa7G=go^8$vMmJ&jJ889c7&Pf|HDdLuur~_Rz9lYyl@|-9 z>HqN{M_L-pW9AcBcTg`dEw2Ka-1U8Lx<0 z*2kJ-jhxphxJBVgig-0$TF|I3;eeL-`!prc#JZ9bNJsp}{-HgP0=#iigq6g@#aQ+X z-*tkQo?>=!P%%6qtIdUuGjh-<8M}{Mv4F1YU@rA!+xKPL*YIW!Bd-_HOIf_RoO_&4 zmpR*T5_43d8;|4bVbP0DAiRUk#suZVf_DDahu?>NoWx7^hwc*>dGXKbs4(p|jlyj$ zbB_{1*=2~m@m;)F+bO;wdJ=b&Uq-LaUyFpKNRQj{VI{hRBL(>JR0&ku+9&-GZWMwi~?P@r&wbOUuL3H-_^f( z#7ALdT8zKJ2;Gs$E*H3>U5?vi3`A7Eu zoFDq|SV4+qsfaugzw0XBS>-ZS+94d#nH^g5-J1|xA0i%xrX@}(M8PFzh9>I&lwh&S zbkcSVJx67lsE3v+yoI=alB`jTb-s0ayM5R$Ois}T;qM|XFQ2t^QlXEkGrK5Xtip)p z;N5W5EkH_r$k8+I^_MRQS@sxNnO~Fh3|!xD|qz0Seb-@Ue*hHLbmP6TK%p5 zd7n?f?<&7 zq@zz?X??ME)G1xQAmv)N)Dan;4?ACbC-^F?b@i{SccvSezEkSZbj>oPq$?hezxv_j ztrxppns6nIUre2qzD)W<>8hri5neLR4(9+@MKe|R_L}*wTJ*}b>!P(*Uomc#av=3s zN|e$drAj>S>Y%IruQj@s>uMOyjXyNoXM)vu>W|<;*fnKP%AC})sT0Bn!`#6;*EU_L zbLH79ov(fnb)>Z0q~uI}KIQIk2BbJW6*LS>21B9(;^Ee)`L%u5PDbBEP2vGzrqq_H z@1{;qU7s=~tRF0o#$T&(ZR)im&fRx_r0?N(PV`pvFZ*te{|WbntHLE=MLV)T>RWb- z)|vIg(Zr~QY+j8={($jF-{(Y7O*g$wRtOwRP7X;GIWcb3oWB z+=BhC+NU^7|CSC~i|49vmsdUaJTJdV2W|{{g?p&)5fsWVYP}a^oukgAGz(f%W$rps#|+E4sXRlGIY8>PqZN3rX8ow2j}P#KM0E}SV&j=+6qjMfEHbcla< zB^73HXZT9^h4UpPDT|%aj;I>W=q|^6;I!Jy>ZQHb^`|QAE#)S*YNXnfSzjwW;{4C(sGll$Q&iTw`}QKLVq9)$ljkp?KJ?^HBC%g2P7P?>+I0!E0)op7Qx1Y(GK1u1Zb4!(*TD#{~@9 zEc^`XyoP?YO59nJWw2_~893bWMK>tx4Q zDd_j*gx@e@OS7%U5}PQ?i%r;f?6P>U7IQ*;3XfgQBVtI{x4+j zy(;3jS#2Z64Xu2tj`b(9NpcUv4B5Jx>nCSxo2wpA>og7V-Zdg*Eaf<#m1Foj$+}W+EhIh-P?QL>W;fd4Pl$C*mGd|>Px zD%Z+hwLQ2o97P!x4sXHQ&bQMDgW+bcS)ZbL3#eO$(gnjJd>Qk-9b|?HS^hOn3^h(DtLbi1$JIUCA-6=WZEQ$ zjP(Ee)er;ld~(N32Pmw^--~oNw~PB$lyGwQ&^2AVr}ZSB@anGeMs|IZT}IpG>US6| zy9{v~1(r$!ex?)jC)G8FuIea0_Qw0|4>qONPP0c-5!pxVyzF#TQ8m#7Gq0wfmd~zc z8UKC@_Yb76l6zLNrq!>_^k^^1hRIzmV`#B-^4LnM{WkfoyN<#icIm&c7oR`e3FqtS zqq{}ZWxmTyeQuzUt}{;gw9_=V>M^X6TS^5lsB^Q5%>~$FxSg})L{fG=kMA(RUc9i3 zu8Ewxc^py-L-9|3)60%id8b#BoxGh{OkGmL-b+0+<)tW?5cbEJ zyT$AzR~r=dh+0M`qKsCX6W-Rj_F0-T2L)47T{;_6p1{*Di=_>C?`5632SwL;wf;Pn z$yll)Yg%XO0sqcy%$amiDSpdDF;{iXO|;ExqPK!tb16m{uNqmYb}Ags4O@rJbioFP z8J!_ac974p$X3=IWW@I&H`&YFr(R4?FO9`xkJ=d=;uOuy_*07 z%b91ewDcs{n~tg=Qn>#6{ONiON7%Dh8Pdcx;JDyGi5jXkk{9A#yx4@KJR z?ufWa58xTOZ8m>h3JQjwQ-BxMPmAH;7o7Nj`EJI3?iir<`spk!6?tW-t7j>t z5Pdgo`vy%p6aLa!@hocePO~ga!EV(7RduI~VLE=Ni7}{oYBPO6hjM3k9*$%g(Rt##QBY zpx3E0n`7K>u)`)D@%HlCqqJO#6QPw^{+6`v$zU_Pk)Lu=mnCHM)2a1_tbI;gp0K8}UenrsrIVrFQORyaonQtoZ3-KMy)qq3 z&BL|HF7sNf_9egHjjQKi>kDG302>ub>pXPB%@4}_%XNCHLc)Vi&-C!!2`ikWW?ts& z_~>S@j+~=-pQn?(>G$*wukqiXR=5Bfz`Jtfi~7X zORgJ7S&W0dbu{w>STdt3dAg6+jW&Vx=6l^*mC-2sd^z;h%E4}aESBh``>j2_7`X{P zPsu#F*a;7*$bO)~YC_%|cKI15Ucsm@sQC`jAuVyt?QFBfoki8f>pJs~U44^Xy79q% zm@y;X{8&6bgAe*ZSt?8?XLY)Z^?GpDM_kQNN413NhjcN9+Ot{>JL{?D{G$7M^T}-W zH{sjS*#87AxSZ~ql-7IdBJ00y=8YjHg9>bcK3Vl(AtcU&7f!W>_^-0x~{QPqo<1Sau;HpVwomG$JE~{?9pOa|e>h1%q zjhdhmeFY}?Zq*OsOhV~pm7@m{+=Ze!e#Nra@S*2U`qw6R8_$BzNBfhu~ zMxWrOR`7gP9XE80ZQAc$$wk^Q-?fm=$`C&4zCe{8?_|J!T zuBtmfFlrarYsTM+k~yXev6iKW>xDVX0V#i|+n@ITRjT`n;nHw2ZtiAo%Q3=Y*xBH9 ze>vfiQH?N3p2j24Ubn>gmTkhGFJG#_#wm7heB^j#`&iJ&eJ3ZADyPzIj__cul;{ zm)Tc)iUV9j51Sw=Yz`edMAe z9xgd~lAK|h=DG)rwqM}+yd6UMHD9|Ru;njV4m6H`k%#bK=PmQ`w*P$rF_OJ$7GtXM9>^| zA1t$tN}FX)U6}_Ueh_O<EMo{g1b>uqg0EZVYlSG>J5-P55r7?l40KSirTBB9m3n;XbvlGqRWa{eLH%# z5(|E9bwhB>WUoKq{6Z&vh+XtrSv|Z$VfpYXHb1T>^|6S#HE2l9RQCSA@YqZ?N$%rl zX|FIjHGPv@{=1+5LT4sVPxwzp`pk-_v;D7PZ;REmH;?3m?OpJ3gl~&OK!3cx)EYil zoo;lUyJX$Gs-pr_#J@cFrWLoAg$v`r8}wst^oshf(!pF;%0NMQvpdGVmJ`#-DxK7R zqp6v}EWJZqo|RY1V1Z6DNP^e-2?v>1x-{GuHlHBFkJvkOg;?3_L!chj@9=AUrX&D!r^w~kP_llJL``I}?Y zn{o8l?68C1n!?h9eA*YX4yaMjLhCMg{T-51R5sP+rILPIgsxaZYqrD!uVVkHIH#Wc zm)v93MZNv9v2TXIKY1$`m2wxmRY{9Y=fp6~N5Rcua+>*&zRY~taI#F-NKc@)^X{KV zS<*6D(zz+gQcLK8^E|&)hp|j@&**JtmFy_~=stnhp{9%{gB*_cQL+PBH`RQS)8tb_E&LKT(eOXv>4W-zFLiiL<9+7VnjsBfjXhB`q zmZj45ZoW?(>LQ48cW7M5R^f-T2L4LxwMcASg|K?=Bs#Y-q z5|TR~ZZL<2e71oe+-RMDiM`Eiw_APli54p%3YS9JwJ5u48+me)uNg$u8?07N2IvZ@9w=eQLpiKaxZEFkSdGMk^rBH;Iz(g8_D6 z>#)oXKJI0S9V(QV8c7#^NuxFpCx2nq*Iefa6;yr946A#qHV97a?f1zc8+IhO{SJbS^vDPAMc~;y# zDJ#$A`HH;W9edox3#ZgNMe%ATYrHD2eQA9!;MFDcV{#8jXBw)7S5)DFd6E4R_aNny z5w16Wa-YkGMyeveB~O}om39Ay{EuCw3k)`Q_2&G0pGtPNSq# zF|7aYwHL)>0oHGC<^|yBCa-QQHVXN7((Rj1=hje)7;Adg-nuyrQx@Vn;f73H~HhYdiqDflw*WGM4UbGaj_KQ$>8S5R! zIYrp8Fh88eHb-Tq@;JYm*<8VENsU;=8LS!3dT)_SM!EJ?$k|8jC-+xO6mQR1<4l;@ zfol^4&k&buse(_j+mC#inM(Qry8G)@bc+{68O?W-btKQ``IIJ1p_*5@S}ph4_IK@v zDgIeLr;5C#&ffg&|6}wxpG?a%uR{I5o>SB^e21<+D>qf=(T2R-h_;(6D!a>3t&BZG zp4?zoMd4x;)|tuweZ}t-`&Em0;ukDjf$!{}h@iJc;!bLDBCkzh&B)Ix$f`YX(UWxJ z45K{l-&G;)ccUh&Jx-$?XP-8%l{}&5bNu~;NWCn=Z-ni>K6|L6=V6p0{JBF$>)~WU zd7Yo__ED?h^saLJc(vRCbMMBgwVV@K5)Hzyb&Ro<#b4588Gr$1o7E+{@E|{D$D7ZK z@Q7*om*ApV=dr02EtMAe#8z{}A(Q014jkYXdgv?9({#c+0Jim!*2Gz|H4&eY3bytVB^fG zjI(ojslMve;_t>QWyA_>u{7;om9h5J1NW8xK;=Av!3xrTKeP2{71^C4sF~fC`+fHC z{>FNS&zgC1|Lu=Zw-=tPpWcq%T}3Sz9H_(E`wy{wf49n zc|yt4J|5${v9Q%hjw%(rZC9w6$azcNxJO+x3tF8O79Ytumz*?88Jt#u>P~N-+i_VZ zOzU1nHW>|X3HwxF|Bhny6P^7ozSh+#8^O~*n14>=+~%V&yPB&SMoh ztz!`1KM$Q3}*%efVF%@(QP+Q;jt;^gTm3B%8ahXs87Jr*7xA97MBxd*z9<5GJ01&ovl-@cMguy z(YF85+<)leCZp76iA_Ad-S>aWag88-C{B67N;Y~=4}FINdd7$Rf1d0((oc#RH4mmf zV!RW)ou4J=$~${#iCZbE55(TvVk@~vIe?ez^<~G|Cs-)rr>aBt;))ei!4TJ}s~eH* z{=Z7qJ>_SsAU}sZeKQn$(w2AK6})_Pu}eI05=IeEB-Snh4K9wO>9oI8;%@8hwWVz4Z3C@JRlLqP%G zonq}q^hpsud0*T#w98$HPhN+o-|3B;sJgZ8-PvJRV3Yri5Ry5%@ITC8*0lAa_ELbQ|BT6#-cx?@NAI1o0E_lP9zJ{^UBiXJ)`-D`T$X<4aav7rWgh_V0)PfKBd!z}u`ml`dH>c3!jMJ81Uq z@YNW{l~ME8wcZ=txx0_9eke^@Weo>Hc!BUe`ga0P{w><)u=}H8t*Pvk++j6Pe9ua= zYd)Nk-@e^TviuVJ{Y~wZPLfgfre(ypA>(Bz>?=-Yq~)aK-l0=e-w)zDd9KBeVsaS; zvz%9E_;|^DkLn^$VwwNgtpUUqmq&kPp#<;WQdY^m9vk2$;rT2)f4_Amr{K!S8g*f6 z7LBw`KK)L;G1MK`6V2yW@BU1$U^1m~EX^)VWV$quH*V>_+@-zNwI! zk1tp9>9cTM9;e+D7O<;T(@wxDx_GH|Ev7({XIXp)b@|2IlhF7W54u;Bt&)!U7AxKm z_b|Jxc9TY{>rcYni}K7ZUftAt8p>_oQ^2#Ffvd>=OK?_lk|KHH)&#m~FeQ=Pwey=U zcxC4u8dFM5Jf-b9`e^{B8jk0hz)xP-DaHQI=bKG>_(<-jxKBPz&LiIBqau5k&;dAP zeJe#%9TA)*XoWZLcaFJ}82+2`DGwXvy($A+F7WXVwfZ8zG%=U)-nRp4%ggXNA+!;` zTd5*_QjROF0(WMWDo^rbI_te=1V{+v;?3+Bxv7otBH^0VS+ng47*Y~%` zH4StD&cvBj@a0v9pR@2juiwvuhva}Sbh3{7$@k{;0%RvWl*jlt;FC5o=5rLtbSLQA z(SO6R@(OleuQJJoi_XK)C~TB;*t3hiV$k;x?)?vU=fv$t;OGwat$;7Hr}b5;veinl zIUjSkw89)=Q)g?FJFja)ck;}yY4XHB>D*UE+v{fhE8H)md+t;- z?Tz=kt9BFb_EOuX59h&Q3hcZ{bH9wQ##vM1_s^}cuztgMDyxat)MAw?So39x};pojSaIq{n0k6T!FAAUIOcPTKIVs$U4RTXuONI^jJW-(gV z6<-tkB`J*IaQHjU_{)rvyL2=AZ421@OGY?ut!Kq~@|?;@eu=2Q<2-am7j%rCfph+@ z|DGIJz*&MFkd<_-8{_r@UezVI!<{!H#QSgJc!iAeh?x)KxgT(TDO#)}&Ho7N$3fk& z47R|asY7ye&@&aB~6 zs)FR4>mRxSH;C&eD3eSWJE=myqm(C`$$a@_saQ;Eq(=PKQq(0+Uaski9ayH2X!#W@ zWROQcgqdH(Tt6(6bc`19RdS9#EBrLnLu=$S>76vR_N2}z1evkS@RAO0Zz?_m^zTy3 z4L8dM@_Mo}@}8ZmP#^w#&nYXeFZrgC2c@a_ck$AHEal#M2uzgIfwa!uXJ*)q0=y8^ z3hR3Y)>>JmzJ6%3OZ61?=s|7u#V5%V8fu$y@OYCbg_(ou%^g@Fw^_Yt z{PTYMvn=_7ewzE~qraRwX(h^%`;Kqdxmu{Mnyi9*n9Vois{HmT7JHuHjkNMCmBX*D zJdt;P(kUv7BO3UcL|a|xZ3QXad~M1qhnyto#IyCq#GUMPja>`r)9e!G$MIrY7#n8X zx3Omgcgfj+7cj`nF!iaA4g7af7dmE--JKP9KH%E|&|)A-@C5lWf+Zq_J9yRDS{CyS38WxT~K zFrOEbJLHqQF5WhyuKMLp=U`iX46A#_uGFizq_VkeQxEL-^F&>x)5o7DUrw@`fmS)f z@2PchHg;%$mi+lZhckeVv?lcz~MfsfkJ)cNR@RkDF+BkG+w(PF2f zE>z6K)-}wdy8YFLPFSrla`OD3W_~-|yBqu3A5M}z&pP}$O?3Zc=J$%Bk+57E1_xk> zL~G{60{@wDD&@Txh90HAYdDEioEjSL_Z6(KFJ64b_>1Mz^ZE&|B=>?)n%}|hCX88& zJqxkHUaB(L%gK)!F2G-+)T@})|DKEI(~fJ!bv>BH1(4buBGN-{PdTWDypciY z^ha54mFr&=P3vTsa;g(MG#I57Haah36fx3h`->GI>Q7zlhn@ARtFE6c<38w=M8D*m zqT0U(-7(Ir9@abjkcPMiuO-h-ID=7EV!uD|%n26$QD1q1@!T06c>SV+;IbwD$8nd=%a`W8~JXF;2bQOD+43*`AOOd$Po5R7RPw zZW>;byKKLQg7a$kW5x_I%|>z2g5O%=hLKR2-2GqCRY#i7JZJMZ>J3hXhX!zW#LVW= zF>|TpKDhiHv2%sZtBH{;Y1!lo<@mjkS3&IwOfy6bweWPgrn1u4qPx24{5V!#hZ~3D zfUXceR5lq-_sqqO<>ioaFp@l(^=?>DA05Jga&^wAIeQ=lu4ae6b4abQZnI z6N8d$aL#^bX6U@z$$&YK*o;?`d)p4-zvR43In`0}?CuR1aArz| zz)9C#(TeDkXtZZL?swPOCi^)bM8n*ja`4)bYx}RQy;dq38a)v`7k%yNFq?GccSen| z>>B5C-|}p&C$Y;x4Dc{UXhZ=t)3vSQ`yPD2xBRe?);vkoCC@l6ZMDOFOvDNUsG7%d zz!zAh5IpRSUZxOw*mv0Jw0AH2+8>JbhN{#DVI_G6MRHcSs#OhU^{;v5YuR-mRP}_Z zcRl&(1*6n=I;^Vmk|o0|;dx{I=mdTacL`<-Gr-q3Y?tiCCq0CRvF3xUUeo*Efc+`> z>a5cuPX_tI#aMToYqd~ItT*NuznkeAGvl6tBdwGUKZc)@nJP1 zmvK);bDHA~wOt#0`!atde{bVs^>-iG?IGftc$!nGa5IFz4he&>)^pf8IsY*hHj}-l z%;I||4N)7Lm9c+4+1*wzu=)(WgRpD*Wr)a3o}qP=A3N%W@9{S`CR%$g+%hR@7j=cPxzSfp z^k02i2NHbzOU=@3UrOL?ho+c1p5RJV6EgC z!^ugvP#hMgR-TlZr@5cOZskhj5Zk9512ZMvCZ8>epi`sW~c#LH03b$#P%8ZPE{| z$@8~CXdT{}s1ugxf}`%%ZKt|SbZc_&t*!}-s05nNBZW+tuTu-37+>Z26yNY0L4!4{+RC>o}n z$gJqS8&m)Vwr#l|{A@L!}g z>9Zv3stU1>)2A83+M;(I?_6Zz5h~tw;xJK5m!bGtTt4hbo5b#IxRs6m;QI;YFbB4l z!q`TYe{6l1>FW|!ciwNa@y!QNJW|X@Fw-3$wQwf$u=_a6@xoxatOD&fNnT%xag*nD z73GWM-s{>>-4z}#7-78ntp}X9gq}edZY1A74`FNhBk5eXmZz$#0>7lClJ0BrB;HEU zv(Rg{xo7ETe)z|_wqmrG>>b6b;U%=u0^ePwbXL&II=dfRL-LoAl72yQ2UL=?lfNwU6#ut?&-8YpPRc#k zndK-PFitL=Digd3;T6K<$%;EM^4Gc_NqxB7K8NRT*xPE$=gIxnYem>npWA$w>=l3J zdYkxnp^x{m)e`-a4|SV=VDA$;4j1LuJ1K!gm3{~{A4IK0U<;>`Ur6)S4Cw316IGm= zY)@y6Rc9srj+@Oolh38N<7Kb)R1J#$6@B}M&8aUXbP8+To2F@#C-EmwU;W)&-j!YN zwikOmx*lIn2BUn z{;o-7uPTlW@28{k;?GecaE+RBlpXU{?E5Nx*#b)5h3@Aln&(v=$64b!7@Glc%lRE(Z4nL&Lvxo{Of;36suIe=&Fuef@_D zDS)WtoM%_>e_I?kmm!jq)MZ3ZA6fFZv^!#wzj?8rf8OPj{yw`|Rabaft}Z&xkL9ea z1Jr(rV=6lLJT3ajJ&KE?wixGaJ4ubqOipuNb8VE%zEgI4D%Ztd({1^EpUQe4;K(8J z!3^lx$yV!ViRE%Z@_i=Cq(9Vk)D4(qjKXS#P(?o-0^e}*VwQ^Lrzl1AeWx4L+-tXE zm{`=o-nB>g%#fM{H4!f19zuNF0)|Ol7&` zbCI$azb8*`^;fWTTXu=oBP#t;^lmky?@a4N4&(9iaPq(BvK@Bbc`vT`9ZSBCReE5| z_?s4SN~&vvK9^>pufo7H>ydtrN{@+NoxKSd4bZBZI_*zeB*&t1eVRTn3J6QZBYSBgjK8Fz?(ZSpw-=Gyri742Ypqb_ShDrKvjyy`d2Fz$C)u^YT4r#UN!KS1!a zPDdQ0wcqw#dm~i9lp9<#>8>TpzZ)i9;Z*ntcMB~JMu$7XZ^9SDU(BJUZs>fk+YF%( z7d69eU92+c zkhjI~wBouv>KpazoQYPVv;0DIZhcy~Qij<@lH4{?WgY%Xdt71an0`5?2ZXEGn3i|)a{Tb(3*-F>wY8*NfOdeXIA+MXi#IQk(+e7(PyRDdzIf zEw1)A9ax1&lGwToW0}%AUaz`8J-MIsX%_6wCJjZ>dhGBmw0S(>|UX7opC4=o)s+@aa2S9Pw=t;V{OGh*HL9h z)$o5~y?1Ee(GW3-E*OL9vp~jAuDb-oCuj1`1|97vM_zSI#r?1@IaPwo-{Xhmgi;3V zwabptQg!r=ESuTR@vr=Jf%>^gwkhxT$EjY=*7Caut8|5vTdk_C*Ia?HjqX-_EqdJ7 zOHm%Zx2&QddF2n#`MLTl*`FLG19auxoa)|ll-GYzC+n!mUS%+!9zK4$YVUHPEb6?k z=VT3+ITp$*gXD=?_AF}Sr*wSfe6s2_pFQ^m5Sd4=e;hvl!q+$ArERo8lkg2{b{Q`> z6L~jbueMakm;9Cd6^NsDk~{hR0o}Re8Adm#BBzRwZ1mVc`uh-@c^-+=CXdOBhdswR zxxae=>>Q*%{+7pP`0S?Ayw@u_;D^yk{Yk}sMUiZcTHwiFS!RfsdNSH`t#gz&dM5hH z+@?^DH;M8;;AINN{RaOO)owCr_>&Ak1_Y}z2>** zk~;`foipiar{`jnPlt6dMy(p&nDQmYz6cd9!l~hrux3iVl!__YQ&Lm@@$8@j;r4KP z7^Y-OdBbxT{!Do~^+d{^l#;29QU|BDN)1zUrKV54m{Kpbw}0K@ySXW|Q?{p6NFAN} zPwK#QUDLgu`ey16DPuk7BTT7~QaI{fM#SBqbra^;3AWv~2q`OM{yubjTJ@#_88?zmd`>ibt# zUv73Ky8PVb9#^_v{ru|NSF2ntd-cXEe_S4Q^{uP_TzULzt!w{YJ9zEf)w5T6UU~e= zsH=}eQG9dwf}U8j=+>(PF4wwL_|m3J*IgNO<^1JauAINp{A#gl<=xeiGo@4NrgZz# z|DJwtx<#q0Q!=EEPWMTM%9*oet&(+frbp5(h}&E_b7B7Z@6VUL@ZyC67iym$cdp^N zspn5#zBlfZT0PUS%-b`iWceyvubj^-!mM@0uO z%sqYn#Fpb{kH2v8vs3L(&pxyC+=PoIuJ#QYrf-&ce75&;tk0D{-@t+o6l|MsUan(V zS7#cYaiGGhTDIC*4`(bBesporse;EE9I144aB( zxc|h8lU2^PxV$o~p0QKb+Bxgzc`k3>e68|UxbCIgdvjLG*)hkOtc^2WNa=L>gH!7c zcimfMSMNV}Zhms}=FN9*ePY|O9rOP_@o#VO=)++3kgg|cOL6<<-XNbWINM`b#jv3sWe8H=Tx5xsZ5|M8ZGw;XJC z`0CM)r>9+5d8I%+J!O1`vsqrvb$9+|*Y7F5uS~Xz7biGH-V^23eKkIV4)Dqct<^HI^`l6>x%qZQW z^v5L*-SFh~9~68%|G2#Wr=+utZsY3Kux3Of7%|J1*#U={8fIor8fJ8`X%Yw8G|(_N z%+zq=Fg8uYP%~R#F-s$9G@yI>-5>VyTCzRT;j{PqygO4i2))6ki3Wl0wwE>Hikz~! zWrHgIt?E_V*qm(J=aEL%)7e~!NFtLeud7p&mZY7}Sd*S^c&^fm^N>cYwJ;!|$o$yY zzysUUcy5R!jM`Z@h* z`u!xWY$kg!9`pC~40N?~Mr>kJ`!eU3KmWe(9+8Z?GnFU2;R^IWZR+-E5tR3r&mS5_|+P8Y{g@(lUB#yC8@;i!t6nTV?_|td< zZFGi5)RQwzzVYcUW6n~RHQWa?C=*Jn_ zrfJgqr3}??($FfUdYgu+gLR+OhvgH|ZJf5yHL4d0Q61>9AcNQ(`WZgP%H?hpuq4|R z>ogMm-eh;`#tcs8i1b6r?bS`>6_N&$=dxW&fyyV(7XOHJga!~7qt%gdvH5X~2$IvO zL)0u<4^3k4<|T=8<0wjtIxx+(P5v($FQ z_^5JWIa--gGt_je?x6jVvzz<52lHn{29Y7-LKpR zZ)e{i-)qlHXNql#Ww$xQ($%`yIm??F)J2@pPWTPtYND3?N$|TQLkVeasCfzjI){}* zeT(Hq^J9O43HU5)5|RRXu1LL0e=BLJcDAfPQlFk3^#+>+Z-o0rzC;Fwdw9Frqvq!( zk!7g0tE*iA#*$*|W2>=#;Rdl~j4AwCig1!JO`kGVJyo!oo*n+#`@(JUjP>PuD;$V< zY{lrJ^nwP31IjwrKD9izF0|dTZE|qD8?gF`rAWG@yYiU|QmeG)r01yzGR|c-&S;xT zC+|!iky4zVl0B_ndbTV*JL#orv23&0Dn2hgB|EQpru?ett!Sd0pl+|@8BV1k8Iv;# zGahF2PH&rXPgkqVl;ucPNJh)}iq?uZ(*43Q?4wlQs5yAwAMkDRRry|cx4LJ#;*Jf@ zeDCq#)9{GsviK^p8-c`ppkZU@M@-3 zbE_RyBWs?S6^=QcWx@Tikz|}KBCuExI}(;*Z=sKFT`Q3B5A(aB zr$v>b@uJs)x!iL2Xre29k;+RvfG042g%$7y_%3q>M}q|45D|&|dayfl2a%VzNr1f@L-Q=dcZ&s_N)n$TnzIhwpvcz_(9hC^)ms$1q;cUCPClcCa74di(=b)U7I__+ zj!g+Eg5v`t0}De9qEezAtpO+XhYSoF$ByzsBBOk@Dpfg3+EZxaE@fs?!dOly#ariM zxt6+idQS$|VU7qHslpD0u;9;;Gx6h8Cx#Vj5Be?y`ffD8ooIphmS~JnkBo=q#L-Z- z=V#}0$3s_r-^pN2C_8jEcr);~|GVE7_yOx3-%IPD8z7>-9Xx*w=euyE3{w5A{;0Yq za|z}#>l0a6dax|eK2#FsW1~a6{cO)>X9MRs*Gq4oFiMO8dF0Q8Aznq?f?n}^DeD;; zr?*O7qP-`XiCkq|!Z(GQcpo~FttZTR-!fV^HZH ztM96>X*O!!tHa8GtU|(&-ja7w*J%&x9ZC0+Rmlr=O;z)xd8l15LpV<~M>;@$O4d)j zkGC225UJ5A;aQ#*yPxJld?e7_#ne2{8 z599&Y#!W*0;6CN(*dv)=VTy^fMF=98i%vl){xEJKa|ARB!~&BJBpc-e8CmuBDW1shi;d=k@_W@Mbp4(*Ug#5p1};j_2Ic7 z`U=xiXcesGz7ZD7e$+(um-I7qHtk+@j`F^&2JOXtz}Q5l6Lw-8{eUqRYQShhU5^!q zw}#$_E21~!6Ulu5a;n6Q@qGFyvjO)xZwbFY*A0!K>c{s---Vk8^q%960$WS_F{jMu z2uY)BViTgX!b5@+g6+asWF)>l{xH5P?vC@w7IZaa0(Za*@LNW2x{Rb>tR@Q(@S$DR>a$Z13ad{t~nyoy=@d6L|UCI!lfs?h^Ir8pbDhJ(Gkd z!jvCURQjjjz-JS(ECrY#i4H-<*&H%fiaT<3fu<%OZp0S&1xo zI6MkALqTXGs}HY*__(~a(j-5RqMRydS>g|nZ{*zwPdAe?0P2-B1@}4y( zY-cme$+(T8Hk8^-p>%874`q3qE}9MK>UvK(RY>xnDn<5cgocatQ^H*|9KCB;0& zRaK4tR63)6o170h!UoSW52c<<&Q6Xdw>C6QKC9cO+A2FD*(KR1o1nU*nWF8a-LJl{ z5-R)1T1q^^>3kD^l<+ZnU(^|_glD)tU?<&}*c5$%y$crygT8s5^Df9$?ecjZ`)fj0 zY!n8C2Zbhto`$vrDc@92mg}8kq;sWbN8Z9tRx0Bi?{l;a}??=AYne?=AA42Pe9M*jR9TAI!+5i}5p&((v98 z8ES?d#~hdoJBqO)1raX(oSc);Ld}_N*<09mnSV0QQS-^G)EX#>n<2a=o-Rohedn*? zoMrZ5&SQ>axmd@Upavj_H^WeOmYKH}Ef=;y^F%C>OE8=_gxi|4jZ=Y46}|!Y<<|0c zvR}l70w=PF>*RFjj^I{uX0XMqPb`ex3ArkCNjfRoE90^!l9rO=lF`x(DMS23;6(^- z4nHc=D@^Jmnp?`&(gDK#+yd5ORweravRcpv?ITJTZxdU@U!*PNvt)gxM)V%Ck2Mjp z(t64n-x&);cjBMOEzk$f0{&USe8C`oV}xL9S;t`+ybUOIfD1H;gI3a&q={IBpT^dQ z1_qA?q`qs;oz@ZN>896~n1d5gM(g4kQ~|LymJ9ph=*ezaVznJ+6f|s_C$nMgB(Ny zrj1j@8!Si_oZ?nNPbmf2g{Z|#qg%sg{kZpn??!M2-j*R}rE;y@x9ntAf+=QC;2hza zk!`%$yf88jad5wKt2i8XZ|0pudHics5W&L9;pE^!pUrd26Z5UbZjm#Yapba~gK)gC z8^05>04YS+JT>nHavo{S{l-!dAI-4spkF-*f9YhglSeWc|pFa9VKk;TDM^VsXqAw)>f$j?N>FQ7*A> zeAtU~=&qp3^a#iTJ!7t8f8yNc9^n!kFDJ_N^8A8R=q3>7^bgdX8N!fn0d zoId+IYffEH^XZxvl|=cqsx_8WPjz%QG@bpFJ(#rt?hh#-nE90bjq?+y4I6{+K)2xE z*)#bK#PekV1*Dd1TqX8?rrQj?LO^E z34Dswqh`Zx*;iOO@S;Q)@)^D@=8HYT`^3&+r$SeP4MHEnj_4&~3w4+V9z<|8vxK=H zwt+liJE)ok@%M;(%U$wmvJv7t0zS{rJC)Jqs;kmh%poH#9qOD#J`XJgB}nR z^HhARpgSr?F9`nP6(J<=S2RziRX5kQ*T2)YP~DP#M7s&p{002Uf+K z#wlVofPYC8k?#mQIfYtI-KEEX=({p;ni@=&5|1e%dxm~MW#G+TW^`(3kIc}dz)T#D{P7l>AiW(yId2HHv#V^@MuutR|KKMiPt zI|EkV0nZBe81JIcC}I@rmSBq{NA8uU%G*kpiR+8Tpp(#U=x)Jf-Ux0D41*T<5m+SREz4 zhNqcL8*Xnjrm?XhD_ftw%g|2WQ2SjyLG?)9Rk91!@$Ye)@$L#HqPs;)MK?gSd4^!B z@Vf9<0ghyID!^IxAFfC+9rdDBg4-OJu?_Eq-3lJ^|LE)J9qnG^cv}_46JXTMpC*sO=9dMuZNx~0eHN+6oi>t7SKAUr|{jrU*A&!u(ZCxAl zc(D7I)!sE9v3_+N_3ZaA5A5(eydlph-|wNu@deOFPBY$8WIOvA^bfU|m{0J?9U$`m z0UsW{6D|w34=bWB z^LREciflk8BX*9IHIs3I`bs{dRxswURLC5phVv8m0WVkhS!5CaASoB`6Zevu6(6-n z4U^IarVTQ5)cz|!Dqe+N6;=qA@(**{Fn^`H5f%8wcyDSEjEJd`3-vnvHP336Vh45^uW9(o!J8;c=%47C0y-!^S z>{+(!whYHQ=VsSWZolWE|6F)#{1-^Z9nY(WxLGmAT{0=okM|>95MS_<*c)GSM?Fi} zm}MGdes6hGx5H9unq*#Y9p=*d4dI-q0Y6FPG9Gd(#G6$)I==3ns*em3t>$m%1rQ;p z1ALlvhsSx6?Elp5u$t@#oMG2@59EIq2nE}OsYrt816T9ZvTSWlvN)wINuwR3WXeCt z?#Ps~8{#Fr?%)ocf;A5w^gDe^d|SN(y`Q}^d|dypzLWm0Sob)Q7{tXyQ*8D2BK_C>AQ z)YNj)y3w(~^{=N(ux;GS(xOLXPUY{)X$qw>8AQ%r>C<&>mE-vy(ip((6{gm;sWt1W z2UMOY>0B5u98zYk`D)$jzUbG52gbfp9oYrw2;~;-5}i}COEFR0K)6CMShyN}iB1-- zolCv7N13JM3qWt~hFM)XXZ17-UTJUZ7ujnsCoIVC} z!EGTUs{^-yH$kwO&*Lu=G!$P{gtQxzdmEHVl)8&NOT1m!STLI3gV&Io%G$*kK^*}V z4{|8rOAno7W^&dd3wTG7VaR=i;BiGpnNCxkd?IyT$}RnERjzD{I7`G5?-E@UR3n+} zL5%n0U_wfEr2kBCAUoWKRl@85FM@u8%h-nm{iUast28|APwJ0~6S9et&*)oWA5;eJ z5Jf_TU=Om5T?KDouxKkWJiag5I=m|QD%d#O2y2C@F&j21_MIHalnHiAA1HDae@IIC za?T5Q3G@zTf}6=pDkCNfSey}Se%)Z}NZUaBHe2($#g@+2kB-xxzx|?6{qSY15P!!g zLw1Taa*o^~el1`lS?o=$a^@(gma;@yfltoPb^T1WrfGGk?U`+yW4mjEdy98uz!)@P zgNdc^cm8eJ0L^nLK%LE^3A`=U1jJLeFySJ!|SbwYzGvjrry&mZp}tS>5`Lc~*@*Y`2>O3Kod zDDq`Hq;DmKqG$YxtT2%tlDaqB@Vc;dw{4>BqwTysY%j1EI_kS0`_4pWLAQlJD{iW5 zR1@VT61J>Fxm%5%-_Jk!Eyu^IS7 zoF<+_^Z7FrgOVy!E*nm39rA`0|QF7Ku{x#8E$yRZxU=Zgp zv?SpncMx)tL%fSV54H1e@pktaf(h&a9wO%gCZZif%=#NC7Jd_55dDnyMC(KeSxl3f zJlD`Jxs$e~LN4im-WAmH7xQj%4#Q)p@v(QgeSJbe=E8Q#pT~tpb6?Q;M;a@2zJ~8$^Rvuph&I(CD)5?I(L6hNY ztXar$VHc@Wxn6ruzbMJ0lV~O?zk_@G4CxAqNtA|e;T5xQK!1~e;S*z*BHOVoVQ=u? zz{Q|DQV=&05>h~3CvPQC&N9(^a9n}YoPt6_c4%o-J$9q5dW8nk%zjPV93T>h6tkWc&*CkY|zC9pAeMN&Ucl2ciXh z)FEA`j_IkCi5YJ)+h=?;%+i!fw7haC7H<&F@HDp8uRUF{tdvpGzVt!)j;d{@9*!5j zBiIcbCZ&mUtO8+y@>p^_-I(z{RhZmJV~|gmTtjCddl*Bam7WE4y=w9+MwOqfI8)W6 zdSK09lfx=Vbrk!6Irk$IGLtZP^h#-Gr+tdYDy=rKv2+@Rj6@1D9aGcS92R$1y}jaT%7 zH99^ju*kW{60G`IGP_{vx8g6;zvUPGTA5@1$+;(Z3QwkiD;?})f$=H!s4gW_Y4-FD zsiTr2YJuXK^b-&loD&rbj&rv%UjzNj2MFby)^N zV;jwCmfk|td~xH#dY95tlD4bA%R5Rw33_lAFqB05=tOKVHX*tX=fu|%CumS>8+fCw zr0Xa?L&%)XWeeAdFtiWpNIV$-9?aDV(01>B}!4kw2v6GR2SpkawYB~7xV(&>HE(Ub+c zVX98@15%lEnE0aLU(P(}2r)F;5@h_di8kaCYBv3yHZh9WD+C`z?Zr{_FX2{nfb@WR zqG3~pG&?^ln668irEjijqUU zo~b=$8R69XLc#5kcK8oub7(eqJsOlUl~+~2DRxSI;-#pC_n5tl;lx)3^IYTW{;8c_ zy`!p6^|_icwew6O+d=o5;J7G>cOj#UAkswYRHr59r))?WmF(9ZP!-9?NXLtEc~&R| zZx&FyTG@`&y{}tj?P+^u|Lz#>8sNjR@zhaxJ^L895kG|Xkl)dENg17ypXJE-mNHuZ zRJlVugExRllN};z-&Ffq6J6b~dPPmK@qneucGo$rdedo zcHa!^C_8f>vRCj8?J9XJ-=pbcNTk~`FJ$DTG}cU%+(&LfU5TdH1m7L|5#y1{&t=O? zvno6_|Cs&uw%$3N~Au64FL zbD&yO+U?uy_uu~R{_d}@@zOk#&#~0k61#{WBWE%uv)2e@vO$_XhE-|J)3&F*PBkUJ z)JZjulwIT@F;CbR=?3B}|FZt!Z0F^GOf?~yp*W%K4Q`;r(>J7FOYfSIm7Si0HuJPN z)*`8CMgv*;TYX>kFvV)=2=s4mTcE|bkDUt%!y_VRV&CJvNDI-IY?e?nuW}9}Z@BB& zW@cCB4=f$>gP>Bt6tKCTgdui3Q0m^|psdX;`)W^B;-yWB2N#tW_bk6u-ORkf%CRqY ztaaDse<(41JgN%c#Ys*@f>dU)T z&a7QxUGIwe(!$50d*XkPKhUEYotRnNTLP`5v;3)?mfjbIcvIOiC_xV;ilc+D2EmWs z6YhtuVeW+YYA}H9!Kc!*nP)g<+&ttNZ4o`ik z?IlYGQTP~B0JWm0#;;@R12?@=9~xR5%_DtKBNmUnl-pO(RFbb~r5>kNDvk1hVwK9P zD^8VUtV|uOyC7YQG=mnBm+?o@dRXVcUiWExL)&pXjwqdTX3(JK>of>KIkU$0SB`ABy!V4u~lUG)zq?Xua=Q-5TC*a4O@X_8NKxBBFJ{ zX?~rjuU%<6Q?a=uSlpyM-#FFTH83@LhnxxJa_$R?Bp!uZeN5Ll`E-geZCJ+Ubf@96 zrln*lXBf2}>*=ku#Y~#&g=K%1v@D622rCB|aqD#N8|)SFg7KUc;NtxKq6zXO?M8z% zy)gYlYSW}2mH(jYIY$z&Vxd4Y*CI=#8m&;3T`I4uoK-W~vc~?Wn;(MWFdXLf5`U8# zrM+e6lsmOP!yj3j>Stt6O=+r>@PQUT_9WQP+r!b+%&EFta;UIgQDJF6AU@-IehTVi zA$l&?fi{)4mGzXB$g?yD46m{-HGJ8yP1Zu)BjNHyFud9$wkMl^uR==lzLkDl^g-}h zSAEH>Lw)*NZXiMnjNhduV=3RSA&lYGaFUscp9?n|B=2l zIi?w=*dZ?A8#()7ih{`p@fNXNk$I8y=)%}D{3OWW7RN8gC&bg@P2xS{GvhuyH5SIS zp{UR9Iqcrydgf?l-)d`XU1>=&w>DXf7mV|an~V*OPisHdjx;Vd-8SE_EUD{nZDQMP zW7^I3b&fE|-feL1b3S!ux&Co2anE)C<+*9qw~vB#+O(!S5uvDp)5F3Hu4}0Y$-dVU}fETJWbpD+~)GKpB@I&J~?RN#Qc#B;gOjkYKj}5^Uu=cr$r} zc}YA92_Qcs=eavLW7!K?*O^X`$Hw4WZ~-&`ehb}YT!(hT6F`8EXf+fOTv5(mAk-^b>QAhM#baeDt zba8AeehPQRCgV47GPW?rk5xx&q8p>~=-bG`NY6-qWOXzpwm0@I_BrN?4a1k>Wq4lv zOnhYAjK9SRym9>J_yB@KhKK~Qm^2gLiQ{ArIh^1UsYC|RpSVqgh-qYqoJoD4+R!KH zC?Gb51EQ@xaH*=Luh5zFYicXCo4Q1qsI_z_P@%CAsLJ^t2a*ExIzm9Sf%@Tq9i0Sp z>Qg~m)q}1>hu}%@CE)JY5L92O0&Jp&u^W&`s{my(ACMDcpn1?}XeN{Zlv-2p^%6J& z(tvDh1?_+`;RmpqnZ)EVi{ahy7I+2R2u=nX_2+YP_lPn-h`U~oqJOghyH=S zfQ;UJcp#I_8o}zs`i1q9)rg(X{>)m%n#yuA^H?a$16RQaGli)HI(HRwD;xnTg;mTf z_#Cte)Qofh&x9KAXH%l-|7y~{0Y0d^f%>Ez=;ki~vZoYqD^0=sZ3ra;9;*W6cOL>KV>}>h zuO%)4jYSS1h*=<#*8(s#4muU^ueSgZaU75X9{@A)pU+Qgz_GZ%`^o%YUABFI>52jJ z;})PYjDXO24OIA<)GP8i)fm*{d_fxkCBX+o&}6{d)Pm^P4dBT5pYzav?$94V&*lNr z!U*bmt^v*jO=*}uPEDs&)Kzjd86f)uzXBU2rDxFx0lQHH=)tjoC>aZA%o;!l{tcM> z?%syWq&!pU-SG8Ls3(MGx0lkQg;5>kW65oAk>4W4}hP$53>{EfgL zU?-p_ivb-L1O&=W5aX-{?kYIF7Vxm60I%kxdxKuuPB#U8Xs7o8{<1S5dU%Xvhy=Xl z4}e_x2uM*j=)WUSBj_X`XLo}CdIK=2R{-UA9?ZbwfP!uf=uJK7kzIf#sRRBt7l6Z@ z7wQL}h6~|)U`Abrhk_aND^v-H-}k^b1OfGvPJqAO0mu_KXv_atB@#GxJY~3`P4F17 zUY>+ML33aslfyg*cZV^kH?#>5aW4SP6a-}TJ1{N}1FGjV;8f0n-g`!`qMOryfcE$b zd|PW7KLDQ40X(7x1A5N@bz-yyJWz7t0$5{q)BEW2pt|gQ;0W-L76a$4h5sA#A+YZF z>D|Ch;TOPo{zt|x0j%3LFshydQi%lZe2J_`X3qd z8yKa30(#2B=nfg6RPc_QfI5gj0oQmNV5Qi=ZS4zvj$R4;>f3-0FtFGYyEh7iKaXH|d{;ME95AeWz;1&lwzUW@S7v?Xj9w6_I z0QzMz)fS8$9q|5$fVHC&Gz8uU_Ly^!1L_Yi0=v&GpoVe)pPfqDKwkjASwgA7_?bhi z=?ZE-Z33+IX2w$J3_OwffSJqm!`r}U)4+M4hHn$FCa!`9L9xUsdKEQ`+D09rLX?pH zNR0twegV~q-jM)aI`9_eJ3#qFnai1GW;%Nedp&D3a}8KwA-FSm2M}BWW=abxg($~a z_^ViNyaewJcCR$z5HXcpKpANxqdUBiIiJ;;^?{Ybz6;jPq0C;;d(abQpc36SXcqKG z!bSzCdw{^{i5u{(xE((d&nN0g80;5sfq%T4;e}>{71qJ3U>#+u;00hW*Z{qQQkb1t Xk3epI05l#rO5CNh=*EEO-kkV9+U_EL diff --git a/3rdparty/chromaprint/tests/data/test_mono_44100.raw b/3rdparty/chromaprint/tests/data/test_mono_44100.raw deleted file mode 100644 index 6f39e7d878e7225b95b3dffdbe5b8d9a6c6ed1fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176400 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

A9tRnLpANPitk%F{*yi6ctX5?zj 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 BTy_8e diff --git a/3rdparty/chromaprint/tests/data/test_mono_8000.raw b/3rdparty/chromaprint/tests/data/test_mono_8000.raw deleted file mode 100644 index 14d35c7c17d95bb8d25604daac35427df8ccd17e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31982 zcmeFZ^;;at7xrB}Gcds5E`hlF#@%(}?(QDq?k*c8?(W&xZrpX_E)YS3%OC^HbUmNu zd%f5DA3Q%j%f$xi?y5THKKHrLscMAyfB*g8vw%`Cl$8G)QSzSZDYf4j3VtW0!j+PrD#D(hY5!?=s0B~Z7ksY>?LHeH|KA7-_i7*i|9^U}5j-JY z4itLjo){>ah$^D3_(Q1DSCkc1MLp4+pXtRXd0Sp#271PAF5XGAtRPPDlU6cUohP5k z{c^oLBB#kda-lpZU&?4cyhLqLpR3D=3XJoXdt&8zIY5>ZGsIo_My`}6WF;|1rpTMZ zStQHmVw(6@JQhzyjCdlh@!dpmL0Dvh+$PS*mufLNM9!6)&EJ=GF+Ar-(|dP!EYakSk`0Y!-3y+}B045Wylu)D%TTWv;y< zuSp-#Q*4ygWSlG}u813=uE-VB#b)UzQW(96e4vJ@Yt^OdQ`JE(lUee&yv$tl9Xm3*%$jQk)z~OIYf-Y8*4-fQHfd31Ho$lD zvb#)IJ>_<=Qam2?qTWe|RNC3Er9K2{PXJQOG82Z$8nKK=`p zi-_46`3Es#R1!s`cqe{>wRJKNoHi3*LBj;GR7R@TuwM%PJHe`E$pysvTxNfqNL;~; z+RGx$-cvX+&nP0ID04W+wTpRvuo%yL2Z=B-lxq&*!%K3oyotx(;+0owjCu>-2XVKV znE5UB!W*ykX1zURQ!qFIw8X&_ml&&}j8lK9$IG`r8 ztbn(Av5L=PuQ)HyFxw2-6dY{izO6*qAy)H=_3vSxhvB(qTwNcwdI4UuiL82{GKQZ# zlwE{XJ*|$Bfzqnl%i64F88a#?vSnM*6uv1Y_Q@Zr7kro}-B^1^v5Hv)iH5LjS?1_2 z;;@OQh?HsI=9w&wJ>SRx(O&!}I;YBPb*A(rDxP4wT~dL!7RzQ>_zQk50w)BC82OWk zeob60ko9FfIg==LXZ#(q7F-o8cZ%h3@pU+4Hu(7fN-{(ZaIzEBr^=G@hO8+ZuCQv`M?4(s>A27iK|t>lI8u*PihMR+Pn zjBrLY#(q1n>>Os)M@F))20T$H>EajPRS>@1c@d917CU5Bm};NwFPre$ji}lVVW)Qx?i4><-pVyJmto7 z*NW3bP!!xWP0Sa5*eU=Im4%DVV7x3>G{<)3;8YFoI-awY=M5*KJh@}LcrN0^Vtm$L z+>{?=OL<#ej5RM2d9B1h;;T3>?ubdS;Z#;?2kX`4dGq*i0p7c(`rx-B1xzrE4CX77)IxAe2{7LY)_Bc|d%=>~u-YMcnymRBK22lg`$3U` zwg1W84aEVTDMTBQgAXpr5m;vl5&Bln1*M)?W*675gry2$-zXv~61JQvTN7ccv2u<) z%l&tV{`Gh%fv{=y{TMO-V(R3g+;_;fpKqI>F4$GU1=6Sld&i%K>0$E-}`OczrJn%44yRl|-RW zmNKt#Re%YAO z)|0J*nCmm{{|8GRMJJU6D+#d0OxC#&i*DijZ*q@lsf>sH1LSx0UpW-4hQVl!u-{8@ z85V4gjtKzK`Jl#$I5>#i9--5Ywa=}q@-XGk55B~azva7^uP6%(Ms^Y4A#wRC;%cn%tIJFm=ZUL*6 z^1KLEOyIPp_?LXKn%Q=Q$Jc|CF>;C=$V@tkO+@i$F&FNOA%nh!ONx_IS`!6Bu*zc1 zD`4~+xXhC8;gKWE`Y_MXbW~fo@fc_^i3hA^E#A2=jc8LlqR*fF?ZP2lS z#K01;a1)(*8s^lYy1L=(p?oCb>r41Chy3S>CK^mWeJ;zemMP*o*htC#fd6 zQG|;uGW=9Hsu?rXv6={CH-M*DVbdDi(;BN9;r`~#u_}4Tk%^O zYN3T#gSYP!_lxBZJl!9KdJomH8k-#fyNzX0;@~Xty+Gs%cVaIB1WzP~Ea9ikS$lI( z5yBH6!9Gjj)RAz_GO|=h)@X&(FR)S_*H;zAn87*JOEUBK!ai4IPqfw-@KKRS*pJ=H z;k6%f7*?GxSHW-d@!1ZZSd$1F!}>~~Sq@^!TlnRFD?W;ns9g|C-?<}<&q3htHF|3# z6;W|91TI)dtSo1?mqEfyFd9z&ttLCc0v^PS6&`8``m2gU*kTsU`BGLv0bPdOkIJ!V zivaw#ggiVD#w!9|>oQL}P!Yf#q3~@J(Lxz0y2!C8!JeqfzGQ^L_+lCnzm;phgIqiD znb>&AXt|)y3@)!yt=NkMQ9_vl4}HPrjo|8G@Oe|X<{}onT#zkak==T9@WKYF ztaWlY9JLE9#miyhu(YT*d8PuRoPq`SvA!wjvtwA$A|HvvA-z%%yuNBcgMz8;ejC5-T+$;BYsZ72M=WnsU!c+hG&X` zrgCJ~Tj;MsVh|ecv-%y?=Zb${q8J_!3#VCSG;=<}+>+tau`otas+9n&IaPdwX-|OZ zs;s|(+zG2D6G=B@B7Az7F~*beuaR8`f!_U~J%RkRfH4KJa7Zjs3MsLuiwt;P&+~>0 zFSsQ|cH?)K#6kQTK~8uf`|@=O=6XX!W643>@fL0wPh1>D6Zb)_3<7nluv{42{uExg z$U6T6cSB&&jwrIKa8jVSPIPJY%y2TU7A-A_<~Fc$1Uc%G^hWP2;2C{b`!TQ-OpQ<$ z6wCpmIjp`Wd{7AMbtAj30_ok*ENNiqBbK-4t`0IrZ6jY%V+@7^;$gAkaCQk;E=#r} z=Psc(T#mxsjx}1MnriUe!rT`m>dQK?MHal}h3eb}&rTq#rpew!P*i&yW zE|-IO%3k#MAS(Bc)L#DR(Jn;CRBDi8B8My<&s{1J@(eVTC+}P$axJXAH|y;#Yrx?S z*m4NiKPh_4RP`J_>IW+gW8}i{?a<G9s)0OOnkT1Xm07YES*!}V@V2Z*^bZkkk?#)2WDdMquUY&x$Vi#qzB5UCY*N#J#z=;Rf{$6CIhy^ ziXEBBA{ed%YYfI-5%PsvTlS|idCpji@Uw=U@60ZoEZc#+x)B!W%JT)>5`gdDvI;-) zU~MIwXY7Q1yotuMBEO)zj>a}~8EFD}X(lUsisd)L4xw<@XPKuSkSE12dKwD6=`B*# zo9ZSM&kO3SV3=z@l~)w1U?8h}E{|Z%Ks>gFIZY(`2Ef0cQ9sQY*O|O@4xKVv{z+6M z$)VKfFR}3e(AP=+ffm`PMyuCh9DlfVKPu%I_547twZbT)Q6-L`Y&;qGGzbnM)_%$Q z!a*6pSYQRVde6$nQS++AQ5~3X82@iokTDlyl`!mioH;iY%fRzxs=8RPItN@m!}A}( zug26*z+)nubR9iqN3?vRf}H}t6(X|MxHN zQ6TwX5}MeVD9Vtv$x}!0Q!Q%KEhx(?Fk@BXK}Atq1wGBMt1~l@%peob=a2(t;6)Rf zq73zK80t{#Kvt&OilG{<#Q%HKd)!a9abkq4jBtcn@)*jZaDlJt6Ez*syQ9cVong90 zbiSU!T8&XJFUX09P@>)W?NGSU23KjkVGm=?g75aBe3E&(3t9FF9xF;GuZJ*`i+X^t zYUsYs{NyXF90_MPA*M!v^QO$DEyx_t><{3R!LYKbF2mXt`PskdrxozwexCLQ%=``W z?!sp0@yKZ+U&p=ug%)#F$dQ+@@K>Il4l1l5a|JP|b+FQjvqk92Pa>I>&V`xI;ek=~ zJnmqlYH&#imf6Gj!(iz{#OQjSeh*Bz^Hd`?*Lr)$;pjHx*%GkLC75Fu-tbnokTd!z z@5uN!u=ZZx+fLqTkblE8hXmT zwNSUcsB@Qrx+Y=;S**K^P&3u7sJr!aGp}HOJ#%p3{=4+F^QpX-VBtl?N(rL19o?Eg zP^6dWU3KNBcd2Z;ieY4v`mAsXd8Gk)xDKn_fnE#Y`cnen;OR|RC6ai$4)(OJZD|lu zABNWYFO9%<2|AJKRB-db@DXCB3%{F3=W#gKdW+pydJviE2bi|QW?#wo4?w{?csmRG zM`0DM0+OKn9X$3N_S(X%_AsluqMkCHv2KF(O|W}&qCOGZn_<1O)HKg!QIu6Wqr62e z%!NsP;F-s8OmT4SLcF_yPh@MyFPJd0kZX;fr%384CMP{-BjXMxs;Hu={p?}D&?YJgR?j|d@Wt>K= z;~oesBp<5(sg;PnNFphNj>uZ-(`r0%2_vVmE@#jf0%LRnokPKORV-2(d{ieg2EZ6& zSWR8l7frnAB%$3e)%TaBMut5-Y-4!CaJ3bl+A1=mT5;KMVD!bdq^swdAV4+HH~qnPzt#}} zKh`^jD%(s%Xn3&Eu~Ub&+;r!=)&@TI7^j#8?M1(^ow7lk7c@ zd^8)?c8Ra|l7+UTLJFfXo}k{pgGYP1a(zJbGSGIJ&xL5-Ss=3;cJUDXS?vnqb0~bL z^)ox+&*9|dFzSUzc&r*WFN;#~AfN7o73@&gZQ;I|XrYO8!rs80xva>HFG9GoI=|O} zj8<5$7I`<4JG_{W3rsr(E^Dtezdtp;W%qfjmr;h$jn z>BL|)W;O(W|0G66p>Qu?zdP`94Q4SLKWg3jjp&+{jMW`&F%En!;v)&YR|o8lz#31< z2>q!~Zxv{jTPURfeBT=V@dx_8Ft%t4Ito!cy}>IPXtuSejf#Rif{z0D=ncE?#gd)D zRX^@}L?${(z3WeGZGa!{!>1SUL}zAchM#AEvm@-vjR5m?v35G>jO6NKptCe~{R6&@ z$1jhtoGZ3#${Lr0>yOMklFU&W)PF8eksHXDor#XqV!JXxsSbDgFwerGJhlBQD$?d~ zO?ZJ;%4B^r!OIWqa}36cWOvJv+H^C#IT0;Cf}TlrI`H}GYHYfJeCvx=3dOre(7>Ci zD?Y;n@2Ep05vPc;@A`#TEQ z9-PmEvz<`K9fB^Ps zSznMSrnFa@Ve=PcvMgfsC(rq;u2JXk+huf=+7UkwLCi8n?1fjn(b8L}!3J~vIQ+E( zA1(t$F=$p-G(a0LVWG~eN(42+wrv=3Cs$~l`kk!wBYCntp38vav^ge&+4>+k5ARh5 z0SVZAKC!zMG!BLVdeC=DphMIQw2Z)eJE^*=u=00k#J@y}D9fJ58|>1L?D)O_Bbo96 zI~F6T@_MpM(FrWnB>$IUwj;@7Myh8`iG6?_HW9zq$ehivsRi|37#szVxhrE+tyBLW zEZq&3IxSQb{4SVW#UeGR%MYq$@%KLV**q0RsYpisicYtZ4@&T?iF7VT!GR~#_o_1$ zgN5$IIe6wTM)0Ed5>H;cLpNt2R@h5_<{z%;4%W-y;lYgJjtbZI>P}OWD5#4ecySc< zKqD0NK=r6P5w2^4B6>g;I|J(OqM{EIM|EM-9-!I*eD8r9D!@4Vsn@r|EDvFpk}&v3 znACzF3NzCPa^_c5<8896R@*iM|7}@)U!{ohhB%{#K>YPURg?#9PGC$WC*&5W!4#rJ z>vySiH(uk5YV1R{V*IVt^I>>x4tie?=IX+%=XmaPMtBP56X@<=BX?+3atbjTMUP;L zny22OCh}8~#VTd3VunLTgE3z!a8KqPN32h$g7c?NZ=vM}IhCJOVx&7aA!A0JC0pL$q~os z{^Zano<}YTCjUMrpXRfUPjWPtRM99+;o;&+Ph~7hvbS)D<@-?4Z=o7kf%ZwDhdmKr zq>wvT-~k;9V>!_rh+R5x{Qy?F1tm6spH(EfJ7AAtpmHd>{xEg&Nut@C3b>}cuJ%`F zQbqN`0+qxM{C5lFO{7*H&&uY(d}HzF2^8CQ_A!jC%9FV4ME7PPaX3!4W{*tDddf|n z=U;$1pMvq-K-#}#c=oo`fka#rYeNyFyC&V0jl_VzSYUXsj6+;tpQ7*ZufnulJ5xH;{nK2_>MFc-x-Zo+Ag$->*2Lu9h| zTS7UnWN=*@VWdA{CuUO-ynz)x$kQ#z?%m1reK|$c3AE3}lZVN}|DyLY!OIZF^Cy;C zQ|HbhA53S}4S2e?zv~WTt>Gg^j)MJnv5HC9?Fei%0{*qJiyr~U+(SQ(;9gB>SA=o$ z)#jjcABJ&=+ zd=L)N>Ml<-YZKI0Pv+1}DXpADqZVVnxiIHzp7A$X_9$604YsR+ePYFZ`gSW=#Xr;u zZDE`=tT7eKZ-E2bqbHrDfq1?O3pHS!?}+xdtkPFZ<8(lO*3p=ezo8tiGN*b}V=ZB$ zpV+=U<2HrI22dvrrGBW(`n%z$88Fjw5YrF#*5=iY>Y_Uy>P5Bif)&|Qt@yLjYSdDi zy|s*gh@FZ~oMTB=XJMy0^f=Ga+xtLuu^KL}L|@yc)&fJzsr#-?xss&~B3#P6F<6eZ@qp(aDu?I~%49u*@j_b&-kC@wc z^5btx1*l7k;UztW>%x z%amx)F^t@qh7z!-x!ClLJcZACido7GMX%5;m-E!Y>RedEM6TSAg4ikRg1-}V9x4*s zvsmFMDwpwme+iF9V1)qKek?0}LH6;3DZKI56wvmPneReN?!iwFP&gYEPk6bHqQVV6 z)WMHf*BJEH4LtLbD!(_?aVsjRQeu)^iy|9^s<5Y4|BQWy6R(rVIbHdvN!>jRi#y}x z7F<<@k<2{j0k!47e6<}dS%_Q|0ulo8UqzI03O$!Rb^r^bsa=Vmi_EPMYAT#L_W%v8 z=sl;Yg6F+u*Es<#w~P8wC_l+i7WV!s;G@oraYW{*S5Ok#2?LGKdV`h8@JJ_6_!sC< z!Rt3H6#(w4;=OD5WIEAu9cAx9KAVZ!xq)`NO4NM;%{{PiU1r#rRrpgk{EyXAK*emH z(UDqjnOH^iXghm9P$+e=QEyH>T_BfzX3Xa30XI7C)mgz!W_N~+-a}TV7c~d9rJ(Y) zb9&`KRx`SMXF07>MDbGg5D@`*ARQZa!-^l_hZZQHrF51J#NZgXL+dTxqJp^3Sfl8X z9)5^DykFoej~>hvv%*_pRr9p znW$!>kIrKmd)D}vc=(8=yHROuq|&yss~w@1f&=f-jcGvq9^BI^X2M%%}Ap(+i-F4y^gLuU9jMhhv_A+iPUx69p=B zGf`a=Rrwfp&f-ab5?k9v73Bs0)~4I%&b+i8h6KDi7)7)c_HDsWU(ofKNNjFm{9B;M zo&D@2PHcFSiBFMDGEi7Y$hw!wpA*O*$N6_F$WOrLPDB?wHQ09qk?|QXR;3%#3ZLyp z)t4pv4P*>6b8iQ`7p4DO9(z6G`Qt&{Fm@aRVHJfHrBbzQlkeSg&D6D+V1KLx?prRauwW2ZvIs6bDovs17E^*n+Y z?gZ=opciox6r|wUII6myDA;f@Ux{HgTd44kfOQ)`ZzOa?igpr5+he(p3W$M=&apPF z%dF{TfA+^3;&&f#Z=oIDsnb^3}ZPlX8|^YIED_Lw~8Ohxw(ecWi~J)GUAAgo!8 zmAO)LwkGE{Wo6y)#YQYw2SxIhNRI?>cj3dk)UA0$nU+6_W37t#W|{nlir^UdDnb|9 z%9>-XaVUnJVH<~Qk6My_>HdlG}h62s-fEcI;Lgtc{_o5#UqG4BZ{a~W*3>Lgg zwUWrQ$Dp9>Im!D&MzOYubZ^GM-6zolJIPTgJZ&C4(;wZ{ow_)nAiBQcP3_EPZ#;V) zE}0C@KhpzV2`k#@Jk+N5@QSFeL&yFbY>~-{p_5=G6P&b$@v4H@uPBdCD4$58=psF# zYbdk`5IPy;8p&f7sm$v$+e7%nCbxp9#sxhQH&nTH3a%#^{15sy`D$gNEtr+vCvF-j zAMuZ%&Ye_{d5`n-T%K14Zc(J^n0?Yj_>(ahS41{uunJHwf^V4%m$u{X>$ z2M=rg3w!LpfUMexi2MNhYVp+oe$tSfzXLDSglmQo1y@0GYY@~|K2^27Bp;aI8d)!j z*m8h>?!f=OvCsh-re2_ekA;gz!oO{)1e!2oZx|zwjGsWVyT+w3eI|? zZ@p1^SA?5Vl2a8cSY-m7ty!`=^Bg4hQgdj!D;}Jr@{>t$bPZIkiB7Plbc^%Eo!oB| z3MT-b!x>-Tk1)=QpTVDQFk~P<>xAb9^K~h-g)7YQiFIkGw?9$Sjl+Z5>HA@*mGU4% zUvRc$3n#bs@%;(VQjUMC!gLd{M>LhkNLXhGJ%)#H+;n;uEqQ`UE~tq0nioWfq#LoE z)zl!7xjGSJ#1e1NQ`)}M zA9%VN{n!W)U71?D1^0EuM}4?zFls#y{g+41?S_u}hP7W|nII51gs2c8=oQ@43rlrl z-aYWiClI?2G}u$&bYT{4KviQhy%YKTH`%5r7QI6L3j__3%y}ltFciOdk=Z-KTjlYa z2^6NVf8|V!6+(kvV_t69xjgrcMDKfuDWJX@(J&TFc4B7dQ6{Irfu=Oq(rJ8;kDI{2 z`{*=P=05Gj(FE-Aga~{`-nNjVT4Q|!djQF*BlaJU$286KAG-WBIiMaMj%CL0LEZr} z;9VlqA3X)S$kL@)n+wIS$FTM(#tR))H6hwP@ytM}w*g^gafl zwOxQW6ZrVWhY$R56XfqhOLrk(ccS~y7RybnM-aFXrL1)s269^9K2fd0;0=k4Vc_mHd=^RvVGJCsox!a_?_m`j zybQnJKs_G;LzA$d4?bH;7kWE&%1$EA36Bf~rPHZL7lGiWAn!ePdqI3Sf|e~r-%3W9 z&b&)<_b}>St6U>S!x7Pp*%oCN$v%8FI;m@!|2q`%e(YC^a~9fe)jRaXKrnfn^=D(_ z2u{RIz^>bfmp`zg8B1tq?JpI0sxenzK)Y#Y@K<2-Hdy^0Hq*MvyUEZl@WUGHv94fO zFNut8gvsYJw}bqq0m!-!JERip+DWKLG+1eJPY>4B8Pv8!9T-?^dG?l?@U;gcoupHA zlwQeobeVQ;tRHi_!%pIG_;@_{)ZR?$LMB)bf;-Vk>dsTn;_p59`!aL4QX_0d0cv&n z5Te(Kn2Cn}1Hj01Vny?Dd1{Fd>L?hY5s?tUmHFtM=gc9$U|oIDtZtmt=udT*no4P`ll+XkR)XL%{SI^pdvA@BpMm@SO|TY0vi+iOvk- z?*=Pagcn!if!_ruP?JGuINo>$ho#a(Da|RK7nsL?hR(jfYOSrtP?7= zGRmnCYD7<^RhQ2)Fik!)%EepGM7I}XtYE~2U>D6yY>p#4kE3=f%9Ga6!$L#@5R@&=Adfs40e{l20p`X`>6b06Mm$ar({tahH-i7M+N*zYMrs1k{54tiYZs*lD8)#M(uei-~=kFL3d^*3_&zcAuYvRYLlCXD=X5iYt$74sR)L^Gcr z_+%uW`Hx&!4pwb~bv4zgbwsLRyXV}$gsYmtF79B_0Q$r5?O}A)ICkS6ki8;U`E<}8 zh5x3JLE7Q5RdCcMxYh%%E3SAb23TUUVy}z?AItguE-IzT^pnnUS27sV^5+-Oq-E7J zJZnEVtVxtyAkyApgVuCjKEQp)(Y4>G2Hp~#xn$*f)V`JYU0LQDOZNMR{5y!aI6(Yf z0{;i7ZfjucO>o9SYuh%yoDU7^-_aj z4i}WQCZH0jKsIv*o9HE5&TZuSJ&Qbn#0%c zS#v4kry7yv%CnuY5**0-3Ny}kp1*|n4Mee|kjZ~z&7#z5+FL1|m`{7Gu$Z$s)i@8( zn(o6B>g3Jk35I_T3dYez{gVh+xN86_I0)Vc!rm4zo55U)5iQy~LYIj$7xG7c z{22{jYwxwx0s+3*ur$#%4CSl6>9QUKd*c7*tavG&-^t0B`SOga?fPutIfKCKI##CD z11`kkXZe*L*j9Ef3oHA<$ye0CFveZY`uAcb7joeuyj=%NR)A&AWK{=NUKp#`!8ZHR zcLA)o5|)ibrH%l%oAHzOzF|?~y%ir-nP(o^Dv1oRfPJglsI;eC{WlgViT;?te)3qZ zZHFEUK}qyrMQ*J1Cg_i%&-)#{bBr@1r(or5ETWxS)A7`b%q9*?X2GaMLCZ*AlJ!pBliw!|IGKNm2 zCrCYrH`!}tjvwS+t*QW-Pr;NU$SDUpHLPUP6|BNLWubIdPLTay!11*}SvB%k3h|-6 zvv~zf+=c;55UYKtN_sLzZ4l9%jNKB9pXX=SVWZY`le7x540tQURhsxeq|BHm3r zHy_rsBhuCs>=O*+_cuXI65am=^jWmN(i9N2h0(Im4|*_UpsV+o&RP`JmXVI7fxo%X z9-eTMuE(;PkUeQ~Pif3e;!n1Z*l zQ9F;w`agL_IMv2#_;)wRo`y%ul5JwBL^Bw<1$)JF;2bXyzKgxDRn#2Xu7yGeNApTQ z)Zs&-cO|PY%35m@kuJn{KiF_M86gMuXv64ZiIE&~X#`KL3M(7I9dC}JlK+Nh|3bYk zW@a~Ft{m1M%$?d^LP@-;6c=L6@nrdujPFe@`9Rz>V#KP%w-abCfi(xf9{zmZLi6<@&$#h~ZelLc zm&`7@JB&03Ol-mb&tU@%v%z@gC$X}Uy^%HS`cDPJ+FOAN`1S)0+KK7zFkDG6py|fT z_@oSx8jOu^ku$W@F>i@e-o|3(e-H^V@Y5}D6^DiY_r7djaA^Q*PSln;FxNxW=MgHN zuh_UHD}Rql8pNr&9oTCls;~!hZU-LT!2>rzd2zZZW8nu*K;x5#WSRlQX%CpLJn{24 zD=~xazSwOJHQfbJSq*GfV=iAf5u}}U{y_$Rjh9ZrWPQnOTj8)+R^1Tm700UYiL4kf zP@B%=H#PIfZE$4O|Ym5+rDP>Fe(on=fDEsL9KG}1I;=3=`tMC5B0N%_}|R^ zPB2j!d|!mIv^PFyl4Z2rnK@*Wx5U$I#_p({^&%_Q0&`P|-D7-gM-lj=Pgj!X>VPnR zdJ})*_jc&Jc&z*fadng5E@YPTQE*M+*Ilf90$6k5oq$BHeTDtXVA0~rHZqtC(UZ?; zok8X#lw}_<`3-E(qE5Pn4N8&W?t!siXt7ZC>L#%&D{M6f_WqZ*fX}G@bkVwlv+Jy? z85a6Y7TN_b_CWvst*((*QGoY3jj;;fc4cH&n9hX7s!-8w2Z!~s-*0SZ1wDna#(45b zAI59~Gi)UGemv_B}*ok0g={fr&6|)|B@Q!_{}_`?Kmt&UD47Kh?|XM)jilLw%=SSGTA& z)pXlO+b>%ub(XqBz0WS?H|oQRthP1#R8d5FAD+{i&lc=q_rtTx@%|@%V<5I_qI$OC zw+VRQ9Gw3MjnIfp-xw9`qTDBgt-ubE?AN>kbtWo_0sKZo+II5%Y8d+oJ?d9-hG@k} zoB+i_Un7#YXWi*1#j__k2Vbos0=h6(J=S{=@4o{f&**J52dT^GUYFyF-F$4p20?TZ z*AtnQ;ilU}_Drswft|}zCAp$H4&bc-m|oLvV~MKrD0?5yx$NM|!#rmQvpo$io|8R( zz(O5~uo84sjlAb|h*&F+nwpGi7zRTBz`LA@hOKYIv=RLFEl3?p?{7c8DM5T{@AQoa zd1*Xj0H|ri8Zu$=heStrbhp+yKLuJJ5TA93r+a9cLcEC~)lTHvPbj@&M9X1zpBJLb zesiv;w>n2Xg$JY59MzW-Bn_GAcHSy{At%G^cZh{;*!ewi5k@S|W5@S04A+@)#xs(E zYbvpVa-eJ#80`f+9j61Z4>Ub5=yGXi;m47c+k>;G^dnwk|B~pdXRM(P-YyMezY^K3 z!%-Z9x$4n>7{h+~@`7EXGgNNVh@`5-c^i;1vOs6gU{7cuXL5A#RUh<4Ine!p_<8`d zoPm6kVpPBs?)Lt+AUkSTZ=9#t8L?K|ZHmY_% zRY?=+O@DYR8M`L9+Ce59M8~)dUPvUr&!dBOm(0yyE1|#E8TRYXxY~>g@%v}^av6$; z^Ox$MRD#Xu@=V8C&!|AO_a)Aw#4A(1KwSUrx>zvOK?9A6)>(qJ-cy2tp_J>a#aKSBm-c`T8#7oh0`C~d6Joe!9^Ps z>P)bw)jln`syY$1ioKKl@WCviBoOAmM-=j=GrrjcALQ`#lk`4(c~^5#K^?M-abr0j z(TKmd+_4%tneW)=sT$Lk=kI|R3XJ+5X0KR0&=jfLZo~)fAZ9v}o zg-6N}w@aACX?ml#IXknQh^Pr#`r*;lbUM1S*EAf@YZbvY{{I$FJR;7{vd4RZX#Rl$ znnTQGkgu zfbgBz_z|&ij=uPG(AXSKatHmIPMgC!-n-Bwk=SM#$V(C(mG8<)e6S-C3hERmN5DKMqR{1@nhMsvi7zAv*8FpDF4|b)I@lEeRuP=&KC+ zAE@crHHaGZ9=kX$XpOb3Yc+=n&2!p8ThpvSG69BpiTA5<_i$o!H5se{@mPaZ7Ul^>_}3TA zWs#pY!@>Q?jAyy}U;H$P>|rH`)ZlNfY+=3gz}r&zPkTS|DjqM+ZR5XScLovh+Bne$uEGCbIA2kFHUapD6h#?yA8$j(`j|6i7Q%^KC4@3VYb_ zmm8TP)ji-wqiq#eo zFN0X+G@|J-F|Pg9y*?mKGWYgaavC3X3$nHs-`xSvJ;)x7mF4(bQ=!YKgg){<$0IQM z0`wjvUhBX+uBf6&Mr;U|%tPt*fUUbJW@RB~Mh4Lty9bwA$lpt;TfU&E7f_2dM`vfN z?eO<4X7U-9`41mlsks=#MmIIYzY{WFi=<|nF| ztHe0xA&B*BoRgkUhUPDzDEo+}LcIIhjuRyviTiHMIv!l#fw%tF-Zqf?xnl?jtj;dL zZ01=X1=I+>y@8b%V@uA^p+U5>mv^byc5>BzGT9fD@!WjzPm1K>0#^6+oiC7$kV7{1yEHg^z}H;I#Ukwi{7NEI@l z7~Mv`h{EHSdG<7RYpN)WitjF{Bke=Wpg>KAcG|wB}Xurjk>5TX%?=cC^4h^JUevVqaN|e^1jv0p1 zn-03(s9UL(n((|xxNwsiqWYo3w_~NZa9A|<-3dPi@YN+^Y6(1IglV+5hh6de7HX4q zWXyNkP6>M@{n)KYTG#N=!TKq`Wxkpx^2gwG~XkCS$=)% zR$DFJP5G)nZTG~krQwUNz5b7M(27CZ`G6L?@5yrbCaK^eM*0vaW=C`E}dd~y~_g6W}d#T zo{nqm4%$y~I`354E+wyMT5^1)_`8XtQ<|mzmAWEhVP3X=wbNF&yRPnZ}4f_`+we_{=U(B1qIV|DO1qSOQ+05h;5j`otmyC356Y#Nnijmm^SYDCp`*hk z`;8(q>sI3HxR`jCv{5jU35yg50+Xp!N_Vn7}^0%&i=F-?25$(U+ z{_-@u_0RUvmlHo`r|HVM*n7?NZC7YxvC72*f?s<|huiwMBHWsnl^tIvBIU#J50$<( zi|qelZ`~4NtF~mJE#!mztEcU7Fk#bSRLjt-#WVmHC*ocnd(7lA87juxw1Vrh}v{>wb;yHD^; z^U3qR?%KkxjZS~r#cpq$o$T7? zbx&7Q4x~TGe4F(%(;>&j=C9xHwA9_r^OaYg&noX9E*lK4wwbyASi*CPne!4>Mq0l) ze9QX2BI;#aYQnpu@oAlNev4<05iUbrU7V}ijn7}4(JT3J(*Bf*siTsg{XQK%EoyGe zpaie9npw>)t@38eGsaqO?S20Aw|I9ov4do}l~XS7P=2DNXU3$&?6_y~gHkVNp0o6` zE|EF(y9HJ)5>ezr;7j*0j**5+hUJDTvR#&v*fcsk>h$jtDQfzMtm}DCMUHWV zdyH?DK!*_bBJYCsdVVzalSlF^=EvnGXJ#f%k69M^B|0TOEUi*b@BChBSABw0NAJl& zCkp)vtm3=Y<-2}IUQXsc^H1|%=F#cHl0U^Sil39zA!BmxO?9u*MPJdl*!7%`DX3ea z{XRn-Cgoo@ug_SNWyy}o=+2+uQX{X%lt}7oHdyxM^vdjRnP8ag86W(vh>!meW6hjK zDbC3iQ{N<)h`s!+@%wS_)GuL?r(*lZt^WNv`K?8<&vUQiYv=bhpikkW#aowfEP5-r zR>-JgXG*1&dQ(&%=;U?MZM*wxPe-3dK3%+%eU1ja3E5FBwD_yy8O45v%=bU&>FGYr zL+^dgtA*=YL$|z8^We1GsV7riQr0KFjh~<7l@XfNGq=69XWsQpTXL@?UHZgq_uNt0 z+fu&8jQDxtd*t_WKQ4Yxh^YNNI`UBYMk+JZC$K zr-j}XwiR;m-Rw5S`I_@oml;kwbRm|=)U8P;lc%QsOf8w7l%8WgntMaIIox($=DOYO zj>|LqgVuBAk*O|e^)gx9iY0iqg zgSJrXmF)egb(03CoHeh?{c6ilAE`f-v5t;jo`F?@6#oRTb*_EwC#h#GVOeLh;<86) z+h@x3(&=d#$vN&eH>$ar%2~Vi&NaQ}_~v@fa&Buc)jm0^(wve$Cp1r9mr*Oba?XgX z?2O2)zw&3ur^*Q3Fuk8~v-2XiVAs=*$;y?S+bP8o)+hL+RyS`pkIv|jek5&fMrq3u zb+J-WnI~T8KbS(j`uaWeo$9{Su1;PJ^TYI;=3-eR&5o&-gtiHmq(pNI>oRqDerR58 zao+h%V9{cuL&kgEG>)^)%B-BcAntV3#mI>01Hb)}ny37eVoH6S7GgVjJUpC7KjOqtGy-8*~r^62aIpEzpilR3(KFymsXCDAcqR?^*c=j=n4=6UIs z(dI5GZIV7F|HxRJZOcqf*%=oX>G~_@XZv5@e*6fp7hdyclejmjGqPf`%4VnMjI&(K z&Nn~G*lw2C7p6pys_sTnD|GY;ey(mgZQaky%9b(m$`Y1dR= zQ@_OShQnXZGhJRfUNKZq`f>JTalv_>7D`pSxlV;#FSsA^oZ~UlInv%>x5)U#dA7$u zkBu%B9M0*R>2Dam+U>NPsCUq%8@8C%du;U?>-WX`iEDSq!^Tu6llxnboo+)-R^t)7 zt@?4gO!1VrTXU7#j=em}1jwNO0(}Gi@Ez$n)MU_kTf5|!Qk|5y;-@ttdy%qQDZ!zZ&S33qnVMNW)h*%gxGC{2sZFznS~9XLnJZ_cW^S`A&pVU% zAg`LWf!L)Vpzop#QCsExFwadMlGr6B(LC2;%(Ga$a~kI~$R97R>W(Xegh997*x$8~ zM>Th=bDrI6Td$nmnM1NhSwi!3@~&AXXaC4@%KM}aRwn4~D4%ui4zaH5y`OmJxSn@- zq93JR%&C=LCZ$qpGjob%rS)k3Crhi`d$w7+Ji~88fFZ`NkJA>{FK!;D=DM@_?{b!z zJyU-EPLF+%kd*#4cb@veX3k&Cnq!sm`Y*bfx_*YI#y=gW8voKyvFWl3B?ZQ=h8IR-KB*U2f;;vc;>5PbIf$cD;qO&E2vsBR#oDa<%jl7C+fl zsUQw0_3bJ;ly%6pGut;p1Z;n&;V$NhfP> zONOPjYHzp4VUt6Q@v(!&rHprL|Ivj`7OLUD#arj|BJgDKM&&M)|5W;5(cQt5f}4fB zDb&FKnP)ZkY>!#K{R7+sw)<`JIqCV#RcHF?RK{hMYoKdy$A!A)wn3JaS-;Hf(yk^2 zC#EJUsr}4fvyNrfG9NJ8nZKpBNs5XOPq>;|IMX?^L~7mNdm`nJx-LQd7P}9Q-cj%;Svv$m1pL;CpW7?e*bNZ~j&AJ@>PR8v9i~gY9P@~Rq zn`4SYRfiwOqxPYOW}xEnE-BcDd3 ze68{0X?z{a5`DT|9&hsdDsT12?3dYBF~lhey7~@JT>E(q^L6+C;Aiq3;(IYj6dzjF zR3W^qL&-`-Dg@sTiV0ZnyVP^2o5}5$ySLX5ueKhmT$i}1?u*>woQm3avU_I?Gxcp4u>RTkPTJVX-Ok8A*R6`6O5pJ|yXrHz$ruXr1&p{Z@|1-(%UG zz9yk!%)Y3L(W|4|ME(5v=0`}>fz zZu8ud+0D%_GXBl%np@QNNgb~|(;v_;P#i^T-C2iH?wMXEJ-fJmcl=`f+o%|O*;#cB z6kq*S`*bHK*K*D$98IR`E;pS!Iel>GWD4{6;pZFlGvI>vf38lZqE1y!+f92NXW7>@ zEH=C}HZ^s23ULT`d}F#`+T=9Ev7vL4M<3rZ0SSI}J&&618fzKWxtsGf$CeYEvplP6W=2Naj2Y>jQ|2d5OYD?5H2zoI z+W7F)dAXf*jt-?99gTMl$-0aBa64!FJbkFzI`>IVxtyBW6U~LwNVKW3(6mCoHH z_c}E2yx?Cd;EcDA`$v}um+h{FoV(f$ux4etWwcMPmF}D|C;fcN>ZJOqH7%VD;V%Dr zMtjxt-0SwlWwJ}IbH3AEV`JTETSnggY!|aj#^bbU$%PY6Cd^5jmDkJ#uhuC2a$orC0*1S12HT6#F

Z2zBD!0!7jqt)3b@^EZ2&rF;3S_ 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 K6m~vV)Bgv2^wenp diff --git a/3rdparty/chromaprint/tests/data/test_stereo_44100.raw b/3rdparty/chromaprint/tests/data/test_stereo_44100.raw deleted file mode 100644 index bdcb7754da9444d4f4986cc364988840f25c97af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 352800 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 RdV8h)oV;Db(-EE$gL&hF9=O;GE z6e^3vfrL#xsTy4Eq*t%;_p*HERsS;esY>E^b8LQP-y2!RQ{qv1G4K#8-U}&rvfMY> zV60Vcsf`_>>OET35yp+d7FIx_cQ7CO;^7nJAbNFPS;zk|kD?|oudS8M_)=WzAdPFis{DMj@+k5_i`JY#dG?Hzt| z&iL?ab6-a!OXj?mEMXt<4EwO0OSUx|@d}(MB^B7Ei#i##+bk()8g%;l?7St16;}qMN3*64%`626C z|K_sf*I3yu;{ey--;asAapv?QKGmC-bYU~|@#(WYW!E=~t z?BDShY`;>*k_BV`@?Pw^8Y6Dy<>;5IJN+$^{fiNvG$Iq{8rSi}wqCKX)9vok0~$0Z zvr6hl)u4JUwYvIvN)sN{(!ZV<&UoD5VMt!V&(f}Mr0sELL~EGzh&*V3|2y%hw!Yt; z7DkimNXXVz&eNQfo48La-|vK7HN<%lw6YPY)pVaDGSL62#MIT^8d_FVOD|KSs^#fjT-{Os>bpZ7Eo!4j zaW-e1q#An_1gg~0!&r&*P)dsr^VaIFE9`XvTe?&Xs_*I^xK!}OUSi3k?593&&aao} zdB!o`jm3!EjmSBlIDLe@)-b2*S-ssPI{gW^e^tMWGaX`w*JUhe22}ZhpO#EB4;2T9 z@x+*ao+N`4DbDbLt0IDQ5P@zpE?A3iTxE~%-<<0FhP~oOCWlzXaF=t!9`bscC%vu? zw85P4UCCm0hiq+k+L4|TyPVA7H?ttbEEc>FO2^vDEqv!EIFjvE3KM9AiJL3JGAq!2 zXY%a^E8_I)2l&ib5_y}3KUPgerT^}5sSZ?&dVX;cIvaBR%wON;>y6XK9T*P_$rvTq@G7gFCC_LBSZ7!Mm}kxgdi@p-HMk zZ+Q0i?zJ5Z*Q@-uhx9Q61u{LPg(kxY2J)4KIfI6g;bOyG~>Ia<@4+Dp^0MX64C6i9HFtbF0Y7T zr{xEQ5+iY%%ShvGk+KupEQUK|S>b(^S$J(#v*wGkUt-HS7;CIbeN_9FikzS0N?Y|| z8auiVw%@6R)u7NN{4{d+A6drFso1+ORXz9PZfKR=)L-N&`EE*vcD zXCrrN?N!0&c}Oym;`OI_bT%m!gicqvXC7GiA4%tOzY4CYEq}gHRqe27ehwZKai5r_ z(;Uu~_jz75u)qBK3B%asU+k^Em-qf)3?ueTPt%IFJZ>Nlt)V{$S?jx^)ohk9nDtNN zNiln}w-{Q2r2kDGOKwkIY356NHW+6^tiYxZn-vhNcOQUJU9>QtR;*&3PtxQ4xbamg zJRezWKf-?4gGKjY?lD&UUSW@>Pwid#aWY{&O45EySLV#LztVhbTtBeS+M1-3GQ{=Y zlYMZUht*{Jdg?;{_#R(*!Si3&&i6&t|Jx&ZITp2;rj|m1t*Vo|==NtUX1|Q-LUvP= zu5RNMMO0|=%GfTDodmDxNH^8}UtBKGj8#7br`mfpWk1c>OHUX!iI!gW?T_HkR?<45 zkHr#~;mwWV^l*7cdv&^+;&e@8Dpjz@O74`G@BEVUHqNz_9n2G@?q^liVSO9%zaxEL zjm`h96-U|s7xJ*BY;HNGu}}PpnJIU&(c4p5bVXKB$*VpeD5pQiS><86iJ5+RJR#dR z^NNedd~>I)D^3cn4M`i&Z+-fS_?(B9WB1i7^!E;}EXM~f_JmtS(1}vp@aH+M zdzppqU|C05^=TR|%Ntt2k$U=gCm$Iq(u~rg;o8&F>r%a2?|aW-fm21XIG5!u708!i z_Dr@pMNT%z?+?n{S%CmDmq4PA4kKo(hpxZa8qgh+UhvR)gv-put_*7(3!#Oh0*j zdJf8+mrjwh~Caj>tZ84pEN%>IT|$5i@3L!n~=*$Hns$l-X!ljXdXqrL}hc^cJZiruI$4?YVn2)ei8do zj?vCE^LFn`6ihs+hFw4L9{U=AA=hQCasKE4F>7tw9f>n(Q{{0Vnvd~`du~pgO8e2Z z{SuF=v$f>8S3}i*VA+rK`o5^XMkM)6wz!ygEg+%Y^iY`BROa~=vDpG*NkLKedWcbj zZMXJ!2e{r5nhtiy8SeQ4ejDcjKIe*w&|(OVKhXY6tL#a0O76K?MX@6*If8AB5cBGK zJt(%v+@rd5@FwgyEU(B>n>ZmaSVIO6h#zHOS~jcPDPvlp8sFc1%;wH)>1y6VKj-K6 z%-NZ|&(9wCN#q@a;pAfw{b_xB1OBgv{JTW=*qw6|%ib!7TbYGZE|kG{?VdR8rCvAGLl)$H%_dn@CJUClu4Bf}p8p9k@suI}-u3jQ2% zdKh23SA330@UYLH#VJ4Z=_c*^ktKh_x?`18tO&|Qvgz3I)x4k{s|dy(dpXCca9zan zIJYS;MB7C|-#Od*Kb6R9M4VewXja?*EnIyc9kj+86YjB;g?A^Xn%e&$IV>}x@jo%M zq9?`J-AQ^+@PHdwUkyyOBW*Ti&FA5-pR$8i`tw_|t{n4{oE2Ulsc*-=+V;DG6SMHJ zy{ci?z@9Fi-cwt~Vm}|c%XW71CYxRAZgG}yaF8LiI2a;62Ibo0VRcOzAnu!%H0>HrOXFD^$OALk8SoI>yXJZuyE{|XwcG>-5h zzk5+;_Xdm_BUhWPM)`%Pb5L9VC6gaXVTYf~Soa3qKVcjOMS4!G5R_UYn;e_2b&`{TvZ~@ zY`ja~n}{HB7RNj?m?1{QesJ|M*ygSUN?C6k=o4%vbErP=~MACynx|v*oln&O7OBhU#dU(@ZTKCECVm z0QaRNcP(kvaPOY}?x&aipw2|CpFk_UX(QI*jq<%NFy&5obf5mVC+|Cq;B@zQ?6uW} zY~hpfaJW4Du|-pwPr z6|fGhh;hFY-hG{ZCXvH*b`Vv~F?u{n|A&gd?O|6NTy&H+$GHXz^(^)aSVCTt^mh!L zjlHBcvCOx8@`zS9C5evq>A#mG+R@abTD?+VqXkDi|5w_IT@^E7)J2%;3c2{@=8k=y zycoicqRG5`vkru~9#R}(^&7Ni4(n~EzI?M5w4uo-XnhHrkJ)!8_ZCZ5CNCRXsUi_Sh~t{=ejMv23Xz#uIaF zk|Y{)HL5_%8*$VFWH(Fus*6b_=%h4_+=oH^$!mJ6j>N7Gw_ue;NjP?n>r5I&Q>zy) zGf(bP^K;KvJFhEKeKr-LF6ZA}A@W+af!wN|2O;PIm>TmMj-9_!9hkNycMuQ;KbUl4X9QcS#w|oC%&pV=h zyWryCPkMx5TIk;m07s`2j&apq()>hf@;M`=sG=&`f;2FbB73D(f^mybslmr zMkcjo5jDiohUy0$Q&;Awa;1qxmx+)!rs7bngT9_btFi1B^wZv}kMG`3gYDF4dy#Q( z@)+RnajBp0(!m;%+#q(nCl;+CwQc(OE!{51wmuPmH+ZdO8Jm6MIQi#JtW<%Uxjr;|Un+}?%)Gj*O3`vYe768z zUPP2DC4V-bo{xQQHr&5vYhLZjq$qaEoXU&DjAGnCZw!eqgV{d`jJFpku9t_P! z@x&QMz~=GBXW+-v5O0M1pa*1VEn1Bh*CP65d1CAzSQ3Z4iCoL6*IcZPF>d%4J;h#e z)9I{_+~x_jn%Iweg1lrVpPI>5*I+rT@qty?)km~52_wtU%OSqk6^4Dvmip4^C5iRs zlw9K+>st~xCr+66_KZBVF}p0t3WD9m8IR2|g3i{U4OFw5$0s&Ai|1D}Fn1fB`p($P zKCk`eRBy6ga|MfB=ZW@wWFcGp^%9*u)*n=i2cxUbB(SY?DRp z#D^m5KY}YA(bvs9=>PCNpILZ?WKi|IUtim(G6i`W6{koblU%Z%mc@to54C7i!bX z)$~$S3$Adt*qt<;CB@lG7t(VN_%lPRV(-3cbQb$=h0KcR*CFw7rYJRt%qHQ&D>103 zI>jo6%e-Q}X)bN}P(=C)cf5!sA`^;}Dz5O{%gG^^pGU~}>l7Nr?s12#kto9(VqQsA zo>&ex7j*r8Z3;_#9XgGI8pGK1Th5BR#i+?)lGcB1n|X{8cJ z>|t9tvCv+rZzt|a{Ah;#Pl@`8C#;t)W?b%bzCW5CZX>4?q`Frw@)vggho^mu2mOZo z{DF}jgG{k2MM~YTi#fQJ)R1EpM>c=V<(|#>Y+E`_C;Qpra%cCM zFHXm-hOoU>y!|7ZJPcE(*c)iE^9}y6S5O!HBhKrH{RA7iYJ}E3&UX9IaMe^?E#v9? z`OV|jd^U2{KoxVwuf_|?$}j4wMaPMAljU3=%3C(Do1M^pKaTP~R`X)&=O)p8hc?Bm zGDu$WHiLFRkv4^~Q|J)?!MWc>Ap9%pjW~qRtrD zGY40CT}$89ve?n)Pr8q_Dc@?<27KxjY-$Xgnu4cnqnTJadJT(=b5n}2vmEafRKK{@ zXo!!*DyUxC5?(#e+IK*!Kgl}A4;ny)9C7OvoU65- z+@N2DaO61Ops3%w%j8~Q`Mb5P8Y~>k@*b!0ZhWjA%(@3Yb>ug7_EGk>}afa2MW@|t4^4OC&@#rhlj^>iYOrutAyAI^i^X{d*PA5G542j06ILGPwG&?C~WlwH1 zPgcoW<4oBXwPH4peuC^{FMz)=-v4m1m_2qI`)$s*V?Hh54ntCH5j-tOadY!hgx` z_(D%P);NrL5~ey4lb`PQ$UxT7&2Bo_$^xgcIJ4pOv@7P)f<+xjstzXS8_(_G`XN~U zJGjhFHva`#zef(Au#=PIPzn||hF6_L;G6XALa(FZ(O&g;Ct_>wb~3X{hh{GqUt^}v z7EfG8){8VG;N7?^be;!Q}ZOeXL}Y6KJ6p+r63JHuHX0p3#bjHzR?X zyr!M@P4nqDWa9K~))Y)*6$7-D%-ubSD{Ljr)#UdV>9%#B*iSJ|E4)M$eFu};si98hbS}j|yW1t}LucUpVXfK0v<``LX|)o+;!Lsg${g0v3nn$gVXELbS2@on zc55gMM~jh7aeVtq_;$MtC&pGg!?&pK7IwDsQ5ye(zO9X872hZCu{T&X^XBiRpZ#VF z&NV;if*=|jIB};e^4*ry?m#4|&4vAf-Wc&5_(k6IUTaQ2HFPA0e*stRgmCT*i z@vZjnSy=KcuKzTt57U;g;``~KhL+VO_j)|%8u}>WopRX46)+{kcu1V^a5G)RN~fl- zh!bM(lXDG%Qje=GJ%u+6z#xaoY8N=q>^2)w|RM-BCNF(-2 zjPbUT+J6I2ZJn~Mnh>C%Ui^t0ZN)@B<`XZc{H;5b8N}nq^OhwLemP|RPPTOrL*2$d zVopy@_!;B3%^~NzqS!mUYnu4m#j7-oF9ai+Vi+6E!YB;env-)|_47$=YB5=l(XMtP z;5AU>klN3yd~dP5Z~%|K$6TzI(5AH~^}rV%f&<+!vU^3!@me?{6-5qfZlgb!MjcJs z)+X8&E8SbuMk`m;XGL{bdNn@K9xl{pH^pf>c4Rm}PFqyKUZByra_U$8{kz{ziHs*i zx;Rf}r^p=@%=bxU6@1tLG50{GG+t7Mt(IopRak#@@w^OwDdm&mY_3FVzGR$PkQZYw zFGk<3!V|01Vo$y?{NrU&{Rw_|*0Tn}^cvV(YuJ1cJD!h6WvkMj`6}yRraRTpka4~Y8W^5=*`hJ$D4mW!6ZyVl>HFyH3%{+Un@{L#J!bU<8OB)iIgIcEwo?Eu zq^Z|zq_0nS@Gto8KU!TJj@KoHOuG6En>#4RMUDL~FFU^S;%w0+&VEX;sf%PIdBnLq z@~hv(#2@(LF1=pB7N+7bi=q2xstAYNr6_%0fDxUBDd+g`5fc3$pR#TazN~{hv5xet zyX2wCQ||Yx`1^_X=KDrvcyjeE%m9DjjB zqt)+vLX)%Zk~{Hu+P6;J+wX+<$IMgANGwzPAI2VDF)r|xy|EJJQg%&znb?}hm41GD zBK@btTZvZ^0~6g6ZLOIup7=oB=2hO&6>AHd_>|PXBH{DsvK$-lL`(PbvZlPLik8H_ zv;W9E-zSd^da)8leMlQ$i*~Q3%a9~nkpvmx-?DgXMN4vL6pF*hdGA%5nHeLne14}R9l zjr`$v{#95WUY-3l5RVG6g@c&u9@mA<{lII!7E{)+y7$SNhSwe1KQ02iL%yGT?i#l7lDkc3S@T`{mN@gae{c9?GeqBsq5mv; z^re_(L22lmGopI-65*Y^`T} z)?=-a6E|Sr6(HLUo?T!2Tj7#-iK`uGst2u&fV9KJ@CTt~ zJNqp?td-C6g4e{(XV~%>?T$G{xBD$tkaiTy+lp`P#L&w2&brhp@;GZLVTJy;+V(9> ziu2%KCjaR&y7}@sS(Z#U4fD#)E)#fQMfeos05f33G@kk_+4rTlY9!b|U%IB4Vp&Lb z6ZaE$IjrDYQT`TavKmi11@Hf*iLXVFc4=3U(XYwIp4=z3vh_Ccxi!9ZFUC+`yw2q$ zkgX8m4egskdNCro0lSU8Q%|ynmU5pLFw`H^x6jzQHEE?;uEb?#JpBf>wyM&;$O6I& znnJSM-T8L7ALH-Y>be(-S*Jz!L+*Embbj*hEnILR7B+#0%z?~n*|7s)wt8o%|)a+?@LLcKzL(yxlk7=chOD ztZrE56WDdsg}#HW+ga;8Ot}d*S(;T}@Bi4bcP$@WCwBiWKK%>f!vkYPVGU`lU}G!k z<7IyRB&?VWIp*rY2G<_Ioql!oCXsw6th*K?Z4CJ$ZvRJeMKGY2uz4hJ?~fU^z(J~! zc0pcMAmveW#DF+8_f;Hy2``Vc?7q;#PsM;`d}$H(veYNT@k0WuA$lTkhD8-%+ zPw~(N?(qqZe}bg8L95u$;%~aiVj(xkOycz3E1qj8$ad>C1D(0-bZ`wp=0cn zGn_RBBYQy1s_ELB;CFTT;GJ~ZGgZZ$Mcd0U(Zfcgel&72m!$i<_dxhQlC?eR_c5Z$ zXnbI(=RL&2#=+%9_Ugzz!S;WuCv10vRD-6H3{3G&|+dT7j8omLpe8?FhMdvsPBhEM|hb6{IZ*_emleQXSaY;}4T(2u9cA8H&OCHur z+e%~0yP)Pmh(21~zbh~A?^*9a#2@(O2{u&3Y{F}yMNLnKpp9@O)g#nR6E zjmRJkPk&vXVy*lNzioi#ud>Aja`@Qmc!S>~KZ?^IeuV~K;N7vWdYrSj3ck-^voFKq zA6<7GT4%e<8P@YFyoi0~VpeF3g2q1CvF7qzinTWt`yWcxk%qI1rZT^ZG<2TqGMVFa zZ@yiUZtKv+{j8`l?UvQr3Mub=k+v7n`e>*f9AGRdMqPW7++q%&p3KI^vco~}=Wg}! z2`q6l&2Dg~v2wufdf(W+JFvfADHakZp;S`sDoGwO3!=E+(%?btoLm+=YQQfFdz~hc zGo-$bZ;TZ&XVddM+8QPT4};XPt9)?Vw*FNYo9Y<{YGB`>x*}6!dly!+FQ}O%$xF=j zyUt$t4e^%tB5_;wl&(1+Cx_WDbZX8hJo6pbm!i?Sq#AfY%eonYKx`S;A3OC-h(`G zn8-H=2YuJMl&kHh^PIo?^VG&7WL5LSn)Nv_1ICW=?ay7=B5}1bz`D*t zyu{k8QM9y;9d^Mz+Nd$b89OWFBPDs;41Ti~!p2JLCsVb8Skn~y*#6gS&@CC1mnN6N9h*qy(F`oaKqxs>#l z`+t;ID}8V871f`KaI-H-4uqgX_;yWoi$ahjPSNhj56Zj4)tF}R&AKF40mhbd-9<9Y z&7?NXYbp=@RGhw;2AhbRP0f`k40jKa_!)?GD^%`-w+{B4IQ6E85!TP-fdlosHXANt zUD7{J;JXA~J>+f+_`quN`BzoMep0D*COc$Hi<{h;D3wc zZqKU8MHCnV4IW7$`Yo`(nEU)Ke|iZXPi6g2lG1Q;>jQ`G*Or)z+CsdmK(3cTsym_7 z5N((Rr{BTemgAm%@x|s)t}b0)}IZTR~jfWs$eqPj> z>|ez;4$#heuW|kwDW+}k^B;ZBN-U7ey^z+5AB~jLJ&@S1_WlvgkLSZf%s(3B?`HT; z37Y@Q==R6UBpS#JXGFIQvd$FqM zKCi+snG*ypX1tb`2Kun9qK4WnG$`qgUHWVxqpM^Z3}m<#o9AF;6}Y zYh&iXSgh}uh*v*xz`TOr@u@9%+cJ6a!+66rkf$WMmlwg$Gd`9nhdQNAE3_l(kh@9Y z5BPn?D`u{jBK`cHbOBV#jSCcIi&53R8*iy9PqzXKdoPFGKyeN#ZC;9n**Ru&y|xd6rLB>rw19@U#2H%9f2V<`AB? z&%2*u6l?j|XQH%oN#)~1^drW%YH3yQsD@hIL_E6Jd-rSE_4IxMm&jw(tfBg9Co!sk zxV4Ra#r~@kJpVB^x|NT{IY4!NBM+aCJ>Z&`Yck z|0cX3Jr+rP|H&uaNDTwx_`et@-Z;QJVDL#vv*s78!&43cvcFbC(N#S(F}QthiIo`sCfB)H35k z*Fd%>FqM~R37yS)P{W4k0I9^|4F4M$~5AeaSbNSc(0Fe?DwJa!}73x#wypTH~lBRpHz?f!TH8tq`i>XleQ(XFKv=>%!bz1 zmn6U6$!v=ie<8bK#u=-6U7Gk!=Dkw>Hjcc9`FxHs(}}JbDn3kx`;X(M?MUG!$bTb= z^cB~J^6%K~IIl6v8Z5Ib4<6~gn6q~iAN-RAea7d$QDN+MtuGP;v8gAd0BW% zzSBqRYw_t^So%NaD*aS z8#h>rH_l+4V^z88!sR?FGH0xbKZTu?g2v5xO#?XG8B+I!&kxf3L+rJSh*}9M=Yi2xRYULx^m|Hp0_&DlbA7S>&UJP3E5oQmDWMeB;Ljx(~NcG(UZ-L0MxyBMZ< z#W+$iGJPmD>av$szQ=Rc@Q25=yqOlZqw(R zVB|YI=4;I9YYaGQ{pY1B{js(^#?&Uuuln+_mVUPPtq$V%O>(oFVL>xKHyHjbpwUHm z^C;F)pPybP^C*o)*Mwe|;RKF*qt!Wa{h)c|KN*P7$YlYKEPSe&u5fz_lDizCFvNM0+@%>s}Qe=(!Re!r%j97kzfnCLq znkUS>NendtaiN+}>?u4{rZ-Uq;dvTM?OXpr+M~|8ZqDB>Pkf(N z#;ZZ%kbNwEmKQGYc^BjJ_4r;32-%*e#pp{-EU%%FhMVXm=0aRSE0@y$Dfj-+?nC9W?iIxS4*vTz@@{o`xB}LG7(PE_S$C#>-ZdVC;PShxW(W z9trpp>sW3TRbq$2cJB8G8ygHI?_oJZ*w_mB+k3c7%;p`$s=6B&7=s7ArrNSvyI+D0 z6G>?vKU-nW=o|X{Y1$ANGd-~*ZD?YpTwytWvUzSnddpG01CzD?|Yiq5n;yL3@Bl-Ou#-UnRjo&Nz zOme9e``O70*g{Vh8tYe1U>3je(sgPtqw&uMaN}lktjZWm$jfdD`(%pw09DnxUrD>x zyvpw|<7Y&no@}O}I>8`Vy+Ut)a79Ju)htguU{2+o@T#&Im3dVoKT&6y0*Qx`c|+Kj zEh6mJ%Q0Bh@DmDSi-tQ_vfb~-t)eIT2fV9deVsl*^QHO{#DSiE!|y#7E=_!-=P zKW$uMXWB9KOVAXryGCnhSv|KyZLhLMLBbm!_CQTXurs-a~8-@2GCOfVSZWgs}W_7VDxe}JyK(5nX4Qia4;G6RCw~ed6j8(kEUZ=y>adbG< zXCpD3cBF7U$z_UL_I}3?3MUquPdx+Qoyt>U?~1xGx;UOz1lDGG(ifh*61Ur@N|8mY zvD4zsSX(Yw^_#teV?J`6CAf(`e>69Du{l63;CeR1TZD6UBDIG2TWc)kL5Lk^g)!e>+5>ucz8NK5{t?QgVlnOOXa+-)15{?h&9^!I*xP|Mw~)z-`5z~A;@ z-D@7xFL32=SRH$x#>m|Je4qnFsf@3e#cOJ@kb8LG5Ek;Jy5eAX^qh7?t!2DO@r2)> z$HGUt$6a#EroP__lD(w&kqMQ>3~Gy9joJ2fq*KuEH?XHz86PXc1A*)Y?A?216+OuP zK01lIgFYAjHp>cwFZxy-+{a;_EQi-j1q|K*DCDxVSg{?G! zo-yhla~m3ZPAj-p!KXz$ISW(xS&zO`HUFQO_YcOqPfql<{=}ZKv1+ZWid}tP*$T?` zV@rccB6gg4S5C1Q%kJ;Wj%@rw2yujSFDl5%q;w&v8_wy-vUH)|WV|_B(ich&G>r6&2Z6tg(Ms+h@2-H+XZs zzEs8s2Kj7;9AX7c?)S`pNaBLTQ)&a_TvI0PUcK6tEX3E&+TAA)uP?2qx5K=;wA{eY zn2XrY+PSfCZj^li+ULAvE#^Gz=PA1gbaygq*W~bIgJh>BrDiYs3X6OomEG{>+x*iX&m4=l3U3i_p+ED;KxiW*M^(>_B2j37CzhyKRQ|; zJAnO+#zcCOct5X6S~Ujh_r}qB(?lP=7%$$ffkeB-$dmH4t9aZUSab{Vw1~JEYZJax zE%;azoPi&VcgN|TyBMy=9F2D{jQ9NY34~bblSOQI8I8uNNbkXl7qOE#)p#k6GD|B4 zL$eXCo9W$&d@|;f#o3zEMA-54Yo52U^9KC6GE2Q)WNnpVa_QnhK3cq$1>OO{)BV1~ z*k|mX6X%r0T&tT|?!|td^_{EOWGR0~4D7;wACpN9!9!vVbvFo8pQT?*s~7w15-c!I z)VLbXq??)W8Of{=57&_GdR3L!g{`33j>XkCE@$OmdUpUe*I3P<6-H^Q-nYY8kzOm161M95%;{x|XzQ{*orR=k0)W%gU>{vP& zQuTyYA+L2LeN;wT3=8Y%`r(ji1zX$!Tj%<{2}V%Gr&Xa%8H}e430B8}8=FgcJLJ0& zYNq==>Te&>c~t-I^{=&P(hLUO#=~0Z^HZL_#8_(|@#N~9r^NBS82yvpEy~Aclll+j zxEg!z2PJNX`g@>Ow6uwe$))a5RlNEPN55Wv*h=MX4jKPW=7ka~tdIXTt#{&U=M;P) zzP{_MrsqY)39xB8S;dOGnBUn&##5JXmf&YOSn1z%d>r>KOs{3(-0fs_O-fJuR4HDE zH7n&nv*FEy>LT+<_p?{b8*-!8#dXWIf-iO}q(-#$n<^U9(uux`f5O2!r3k zM8ELfTo&8gJ?7KrYBoC;`CQi0FgJai~y%bk`J#Zoi}*=B0X3ye@>8mjFC2hiZN1L zh?iXoA?oPUo%&dnca`&7BP{k&mCP7%>8{mtM8sFw^%#BbOqa3q{DXX}D~oU9`7QJ! zW$_m8P4Q4rdPzvbcg$5Z?Boi7iLU2)^= zzIXXa%(}|2r`OP8Ua~3+i|RnaCb;Nb`W$U5iB(_ao|oyte(m^~4ZXw97OCBSW1z|ERuh^8P%zN*|VbJA5gE=adjjJG1VUZ2YWtR2S(gxzpwR z>^e*#&LI6sU!G@^u}^iJC_jo9P4k4<%l9=S9?cV%CqBY(zcya-g!OUXh`Los`7Cf5W#yY`k=`Uoxi;lkG zuLsER4|@ApoLQWTFb`orT_8^d=vxp6$fd$mjE9%yxur3uQr>Gs%fo0jPT`8&b~)XR z^!wc+T3;wMK@3_BtK)3JY}S6QmbH;rL~L*4_gi5}P0^vP*4FT^h@VABCssq$poyle z>H+^hEPEKruBSrY74Yh1HaXv2KJ@c@9{h{fx0u#fMqan4YCeyX>qzfD=o>9uTUFe- zNi?YEyKVSMH~+VB-+DeT$8&P~Z7c7J{f=LN&|4tXpY;4QwEB{VZj&K=36s7hpD!TO zORkyg|ERNW<}-U)TjbYKoo~ZW+Omu`df5}>8JHS7nT4rsz>Uvo|M`j8a-5}dopm_P z?{d#C@Z9J1psyaqUcs@?XnXI^wc*mR#oj0>%#Ou!$k!%{)BuWgKU^C(I|C<*Z>P zONcWSazoEWIfx7vuCy6~EUPdKtp|Oa0srgN}y1tGWdc8FY6^zZbQ@v@y zo6GBMj?DT4x!UsNr8(P^m#MT}Dqp)!P3;={d=&P|QGq+|Ozhm&-(O8OHAuZ99d#j} zn((2u*cWFKEW!leBk?aWoY=qqC_P-t=3_Qv2OfMY^lr|I2EnIT?Hu*rj<9|NyLeKq zVI~&vDEqyKZ9j;`bQ8_0V{5m_Daz3Mt!8mHfyQx~aje-L0JA&EcMI6h`Zvh*8!NvE zPR6W)7@vPi?4KYibn~oM7w;FeD zL`seLdsIS~Lf>EQpLh}LEv9Z2AOC12-Y7vO+=124J!+FwP2L`-!4wxQ^26lw^dNST|He4W9@*lRaG(XekJa08-fg=7 zFM)08?s?kYdiiMhVt4=79$!D&DI6P`^aIdT;*@lDP&DgVe?WmNHfFJuBL%n*ju$2i4cjJ z(sd`=op0sz_i8_f#GJH52VQk&;xF~CU22GX)cjW1A9qFCUB)fmP#^n=&uvLukeFeP zXxYR<(PkL5?JS%j2M(wf0=DeZ6^%-ip@SKzu7D=?_dsj zesf$i`Ah{!HkQtR7CDMTv+AUE3)x;Qwr|ImUo%oZncdyT^6Kkr4Z5#s9K0?stnN+? z>3Oz0#OY9R-otKE_?J!&;}U^OG1`4_7_BLbiHlmMU08YvrC47WaX=Vj#Z2tSB3Cr8S9=lN}dh%nl3v3u_4TJ*hmWo!(8-i)<;j0eTZ zj+rd;1{|s@KODy*V$6OhtDa7iZ()!ho8|H<&mD=ic7d#cOn33>-t1*O%YBlUbRv!V zG&zD5Kf$h=z^TpPI%#nM<#E&tdVOWN!rV=CZaK+Rz1Cy~HyQkx85y z{IQIv7sRa(Y1_DVkTHsvNg*G5dO`K!O7oiQ8!KvUyte}zujKcWM!nxuWx5x#Ue6wi zvV++9t_(hQ4Yrz#46a}u_rQg=DZ9K<{*%vm=wFa&9m#KiI*0XjuNeEOEPH|RY_n*M z(rivP_4j);(3Rx2!|xUDb}#&mbzZO1=)J7BHICKR9M%42JIo@P7ofS546`%hGVt$P~{-NLd%&3eV zq|+eiF+bPw`juL|1(F?7Wy;6HZ}e$YCd<%HLE4LTHOGyL?J-uc7yJLgJ-+3gd*y#| zCPwTuw~lRp$#x6LKg*MPZa5O7&jsA;xNPYid2-Y*9w70m;_EfM;BvlJQIwdX-RUyP z*6wzvadoE|r{eB)Mr=wL*}Ozl&de#PZo5yV{I%rh;c&hdjuMNziV^pE_7GO|3_N_FAK2v!pRd9So3Vk1 z^>ZSf_EO7g09Rr@&HX+b0KKBNHIQuk;z+Ya{7tmKfh{ax-LtUX*i&dAX-r@xPrE+W zqEGRxC3?C5;!J_jadJzXrd|&gwH1vz^1ilW?nq-opVP{fVt(vXc?-O_oK?ii_`|9k z7xA|~n9f)nWDum84g+RkJ&V+X_o$@q!}d2D5!;0I?U2*##prj-a8^RC7!lhAqmKLb z&!WvI5Ny3nYp&e;0e5){x7p}vOT@t;{CFh3xB`a#53YR97l-okPGnt~JpY61*&;`A zRvW8_X27J6#jKCSjrlz7DL(g-xVKsxpYs~$`?tAvJHMaFMrOk0z<`l>Lqg4^gz@S> z^r9Wa+>Lw97o8@^8|Ty79R4(g&upgM{9*ms!-~_a%G@xaKh zGv(-o@Uk3PV5~=Y7RoOZwc_No)vP6Ei%k`2pCY}-N%Iw+vJnc#KI?__`~rA?Gs)cR z$uT>9w!C;SFK!`1ol9D~nskB*{=7BkId=Muao?R{V1Ia-0TuIlatpQ@_tF-`xQv4$(eme`%-S9<@N-am(mAEa>cTDabiZ*GOJ`(gABGxQU(vZ`LU zX;mv+HFg|%k~NR!Nw4#aO(M*G@;zx*d0L{j-BcQwwOPw-m2$LD-nd`MM3+Q6^E%&7 z980WCyy%+0`DE<&cK~ONQ((72^4LK=Mx9p6W>3;$VYA~e5N}txwk2+z8`^y)hQ@wT zZP;K{R+vl{wI^jk`+Mb6PfusFr;@eJI;cuk)r^jn6yFQMoom>53A(s}zm;XR*FwH( zYQjC;qYL&GYu92P-T-(wmu)YEO$+H|1fQD-eYdiJ7@y6LvxMv(6_Fq3vxBg|ZldmZ zlK8^w47tSl_NQp^qQqqTp)JRY-!l(&hq)+cjJ5sDhJTbd{YzRq@Z1IR-6!d98f2Qm zlV4=nPt)8eHb01LW6!Q`K5qpPVo!qD?IzAZDI;^ZUp~?s7PQi$o4kLasyy}~`j+68 zc`?5=_~Fy?(T&N<@~_D-eTyFct@h%qG%@la(P0a&SH?Xuq0TDRjhJUYNY0QUE=@8P z(%oE;X{mhmtPJ)V(up%2;>4*x)ih#$)Bmku9t-V8^3_IAu9~)2#$L*^l{&nv6VIyQ z8Mo7V1KPZv6l2%1gEE>e@|W+SXo9^L_etz`*`6$8rpH~rUyO9K_+lZkwxYYYVCw^9 zDI;Aw)&0gpizgxVII`%6kvAf<*mX13_Ezz%D*QF}xqseu)3hnh-QCZB56Cr+@Up+$ z^}`hMKbxw8&7_I-yl0iza5w#wfDO$&PuZJ<8qJw)^ z_GvD*z1RGfID6_1*c~1u_|dOG;b&}9#0O*iMiMn+2Oq+Z7UYulFtw1 zoe#6l{t&gd@7(9F*h{z?%&qATz34N}fPac@#|a?Cp~Y~oDP%JU%YKk-MtQxUJ-f8= ztp0zGtFKl)dY?4@;Immg_85y?3=7Bm#!UT+IST*ibH2pK=2(4iZo?Mb_cJSsR`JSZ z?lF(fpQWcK^|rD8ULl@cX#bLLMgON*qB+Fmy$iZ;6r;LA@egpe8lu8+{ak9?doG*Y zpDdR0zvuL8sGdZh+vw#L`nxOH%pNBBb4JU8${BCV$?lTOm3%~<=}~KF@504~CVM15 z^ZOBu>Qpl3($y!aF|gzl@-7Iq>%!;mblip3+Tsd5*wSFLAFAp~8IDA1ATBBzuXyH8w-c&oR{h zJ0&_Q&9_+XP)4orFTLC#*H}(tlX%vAQGW}LzlR6C0^Nthz8P?SG1l{fzK@s5$LT-C zF|PAzI!(q}18%h!wXYFZW6bp)e?K9X%!E)+=y`Ki(N6#SLaWZQx)L}=2FBQ0RM~=i ztzav)+&|_n#3@I!MenZuJ>Xk?Fs_~{dz>fQ5BAhY#rtXWG0Sgpe&Z;u=pkpUMN^fu zEk+~<>A?ay+bd8c)*lZg`QGF(0s~$`5-Xt8Rvh$Cz57YN@T^Y<>Q7U7ctiJID6`1+ z?@AH01nhZ;SG~;NK4-h1z`CaPPWs9|m6l}pLLvua?>=qQxRqWhCU4^rqt-Vf{Rz3xy&eJd{wC1lz?$u{;( z+Xx*>B<5QayTEwSAZ;#a3~RCP-X-G1ES@^7s1cst3i7Tr5>=jejn>*3X;l*o%`f`O zoW_6CK1lqRwn!bNuXs`;(L?O$%Aecut{5MUIRm$fI5AteD6U)#G9Fh?`Cd%@jTFwA zL6Dvr3n}gWJJrt`slAkB3c3c+XBe$>}-PFx@LF zujM%>tYiIy-&_g%>p}P??p+5jxWmZTZE2l6|4!CZo2Bkd*0Kh=G5Z{>DsU#}FeK`e zXln16%SiZcXDT{Z&_WuMHx(P<=`lch0$@TvpuP{5qItBq?^5uxYEjPoY0 zRZs4hxYul@_K78IYAA2|D*IG+iF3Wq?KzY0Z0$2$&P+b@&6)qsb~|^4Rs5sHgIVd% zr2m+)J)>ym*^DPL9?h7L-aCDoeFkRh%R<&s4ZC>Qe5pfPI>OA2e2KnkJ=Eu8Y^IO( zB=wB1UT+@MpCmfi7~W0J(5~iny^~PC_w6yV`<9qWMR?IqmYYVmWAV5G>JQ@*ucviO zjN&2XXsNq;(a_|F+4Hj3o!fD)_PKKBN}pSM_S$nFoSkrP+_~l1=Ost+$bpFu5?5qY z&A2l2yv*jAS((!_T4Yp7zasr>3}ZNJ?*@%e!`BJPD?ICwC+lXWyT__w4Uy%bgiBD0do%9UuHBjYGw;uup7mAMdAXYAx;)qT zTFsA)oi2Ljiqo&0zVLL{)5lI#JpJsc3a9&>y6*Hlr>dSVdV2op z5vQ*_v;Xw+Gvm+PdA7&d-_ABYH{{%f+10Z5WfwCWtuzF^RjyDoaU;8~nXxcqQ07ya zcV`vM+LYBI>kqQroYf=isjNEw%9nL5n>Ejf$qK|Gxu&rgoWR=-Ma zHI`C~=hu?`USu?4H+~bd`3qnMAF9Eu_d(QWKzn{;0yxy<(`?F#V zUHh_`I9<)0TOF${Ld=vOeSzoq6qUM(6@Bocus2EAqw&1z#~EmRO{FR9ZqbM)Wn`siG;nH0?!``T+#^m?>=bbEA8 zbX@d!beYc|iC^oA15|UES?yPe9bye!|h8@BOxU}mQ*XcIeH|yQglV~?&P+~BaKRS8MOw*}mFXqA) z#;6@Wg%|H3<kTwH%}lEuu~EMBXDrMwzbV^oDjv+k=dX){ zZ$>sI%nxg%&EzbYI5ko`F>T_|#P^ zri%z|ji+ad{3QeEX0+|N*#5i~>}z9HV{gVrM|VeWCO;YNle{Q7A-Qt$+PjDE&bd4K zZkxLu?-soK{@uj8P46b$ZFx7}-Pi8Eez)}9Pw#fPyX@}4yL;}YPu>ri(kZej4bvCOVA|6gT+sr0&t%0@9GEcwm&?-ZF6$(~q2kB2AL zPnw&!DCuBgkE9ieFC@K{SRm~X2IiMT?47T&S%(#5=gVb{1Fz)G1!b7woXpXf*`xBxy|H0( z(wEK0yB!;V#n+GJbN%_~h3Ks4%xJslbJ4e>xuP#eYqQKD(dn%CXf&Ic@Tt?pBD}wu z)hf;7yBjWwWlZVj^}0IhyUz5PA)~lQ_EFn>b@TZ6!V{5C6UNbJ_QaEs#fi-m3nk4W zxy^}HVbk&~9?l*`#$z`;xXNO-Ndv^hHw7 zq>22oY*N#ttM0Hf@qdY(6UVc-T8Vqj-02>fYcJxqnAtO;{1!PxH7wvy%(Wj5oni*z zFnLPN*uT*iW1mLz$BIQSMz1HIi|$L_9X*rWGnyep#<&U*6Z@Xh`yfvgl)sdIO&3p0o!t%gU@Tv<2IUCYV^?%rBzX#4U z5}(~9FFDBzFQ`<8bA7hK$M2zI*k>cz8p*IGwJ{tm%y+B#eK3!lL89kn`pso37i2o` zVdy>NLI3dfYVxdW^n6NPJnY$V)Kj-0->LU3x2AVi zWPIc+`|2(bQ@)6lPMjObnz+ot5F;a}tn(cwCf74}rF0~(n$i6{@1aP<9H}I)E9$u0 zaQJ2_0heSHb8x|NP`)izp3}*Whg8ycIPd8j6^@bkM{_c&5-S?Z8ao}`6#XAByBi%5 z{V%$Jx9y6?px2YJT7K%8wa_$HDV|Y&5^IJj)^TQC?O1y@xll|=vG-;T3@oe_Z0LzS z_~=-WrpU-EkYP0Xek?<*BDVXq{Q5Q4(aK*HW2s`v(a+&uHSw@gv=7G6 zJzA94z7*YuK^=+?<*O5;m&C{u(NAONqNQUO$bCU{ShRQa4-s=ZDYudX=9DK)ka>S8 ze<&*}`9Y*^Z3LilJTGj+ey5UD*mpEF$$luu33EKILcy0JwIh?v0a*aAM~Zsy`FWY; zz2;R!-;XBT#*9Nnva!6RJVYxZqqrfvI2Iqn|3w8iWFY^^&5s$&I;$;D$v#89w=qpt zmx<()N1USb9XLe}41J_}(Ry>R*75FeQq>bi$EM5NY8odgq0O)AQCA}$VSer=){#X{ z6Kc4ZvEOitRA$wezf)?e&^@UxQ(jG?r}3(RaAHiTJ)r{AT6`MIN>-?XoyKGWmQPSQoB-jcik?G_Zv3Fq z7*mZ*ux_jr>Gh7Zjtn$PUbVZaMt7R><@NJcl8YEU5JF90L^;7qrugW{z zQ`)ia-fTOZq!QMfW@ou~wCRF&pU1LxK$kFTd|Pxc=^hQ;cYr$&;Tdhb^BP?gQ71nE zfkwlt@H2`B?6H^bV>nnZ_0tpn&ls6O-_7anHSdS{!j-iu(X)2pO&`j@3-ZhSkgt?F z*%TG_M&x`|mY+wxDz!{-7ky6h#L{}Si{ys0t70sCeQcAJFa7b2QP6IO|JTEh<>ul1 zCp!t}%ZI9Q6}qjYit(tbeLh~>mBcT{*9W)J`vLA8PBUn(K3QL7t*g3OXCp>PMmpVa8F#$P1Czd0ZL0(1lfpNs%XfQd2hHktep6b-rv?)8mnk`Ss(jO2>1{ zsF}aQs`KC`>HMD)Cn@E+DiENKS5G?Z7kNiLy%|4#+g(aWI^=ya zS>}_Mr59$6CB=kV>Q&8Dlfs_HokfG*_HGILZqDKfqf|0J68GBpPCNXriQKylS&mX= z2|LdIgj=Lz17%r49kqdq*mxe5vV!qBxqC(K_2SJUR`oT_tz{d(i!f(Z*utKcIr&v% zc(KsGM^%8rxwhld1xaqgge=~Qfvc_BmMHPRv} z8)C&$)*ESFY7OQ(ylW1&^ri1?i9IXFdfPg#$@;lXz3LS0WlLyg=4x+PHyJ;ltJbnp z<>@50cSY86*XwEhZfX_H2WrDT^kSL1Tfo&hnBWzbo;7mVdaSU2<4$#q>j_ClYaWlJ zXUR8ZQfb)tJ#6xfGt~B24|vU-#3Y~pZ9llA$V7a5msmAlgsO$zKI1<5BNJhFd$rjn zq!#u+9VWVM5>3^G$5lzcS{%E=j=SNs@vyUVL6xmz(5tifmrY&ohU_dG#O*9^466uM>wQvW zsdbHqc#nI1ghpzSV&x-J?#I(Rp#dirJgV?68r!Omdcjk%Bz7 zmG!za#jTYh)f)4r21VMC!E>0-aoADE&#ySeAl0LHR9kb)sM7G9sLb|s>^+!N9~!;I zpDG*CdIXXcOxZ0@KN3q+PyZYHIS$Ew@!BgpJ`CONPw5)#hb6CLO)HIs%~8J{%{M=R zggxQfSC~oI86uNdHXDn}Wb`HgZ+XwCB~Pm1o7MSy8Zq-tehvbz=zk7!5q=nn%o{yAK0CNyeLDqzOU{Z+!4^jdLnDu(tp z#I7h7Z(^kxv7%jke66vQFGa0!^n4 zaIg3}mF0#^?_uXPbWKIPk8*!(-b*Mct&6xX^z*e3pOMiY(H zO)Ak!K`h}xEz97psl}Xp?pZ|!S=-euc*scK4729G!evKkSz|Sq%3^p;Xdhk$+~<}a zAEW1es^{?q1y%O$)8gUNMsez}fw$m|AMd*bh4-x`jS4(8F}%+OKdWEcUOWAx!96w3q4D_FzuxQbZ@V?LS96v`pml@ss3 zHbXi$94dxQq>7wWm@Bp6=dn7ET!|7x< zTD+T}7TuC2iW!N%mxiKnA~OzA(MCEPneruf__@j+W<&0o8|n@Vy^M#EwnVo zvlodjo1pSEEqqsNA66v}I}d%qJJ;&xRlPkgQ~H8;ej?L*kq6w8?H^Ws+70h^n|pp1 z;+=q3f5kG9SqA=_)%em~NOoF`JZaSMYx|$J#QB=XK8&@ML4Tm$@R`ct78QfV-k;@^ zg$RakZ+hwpEBcvFu+Um7dl=J1clbBS=uLa? zl`;xe!RJjONhd7zQ@S08Q-u+-Zsvux#`8zf@p7{&{s*=0Nm#&Vr$eY^aA3aQXIcOF zBV0b<_g}1D`~RK)_prEm5F*IsbF*wVlaW(^%zhjJ0hhpyZ(;Rn_uI?@cEj5>xYG=F zx14?LVX?nxPuMB)CmF^G_xXzj9)tN#-EnPkZ4P^>wqV0yENqcF)N1pKl8q46;`QaB zK#JXbx zgP+6pv(j-|95y?7)b*XonCM0|+#Ge7tV`YhvRV_h+Z#ZPcuPyW(WObRo`8$p-W#<;rC*Z>(**cEFe4;dGK zed<|@;qrG7X&RIs#s{0hsVe@e2W?;TY6R(L>&bPVlq_PTimddSq{{c1HS;qPx<}S0 zd?FWlR3tcRX4z^z2>TZQ<@(|(-Mu32EnnKD!g3iGxgbZ`%>NJa|MN18V{*j*L4tu+ zR+Nytq*0B`6nPh>zN{s$L;8AnR&_H9p3<`dI9mm?T3U%Az0F<=bEp1gCr#D93)9Y9 zw9rSz=6!YbTm0;^SR-|@#(ukiaa4wn&CRu0EW7=e7o>B?7xel;_Z*HDIMq@{G7ip8 z60`fj(B^R9Ew5(ATF1)o+H@wu+9n1^euSFfMJ568Is zTnuUf9yLgRo5)39Oc@j_lhP|z%X*R47)WpO8>1ZqVO>K{f1Bm@(549_GuJEZiMfbH ze@l+rdGkm=c=3HoPmy>H=DbZL+(v_IA%0j>_PLla zh)sXQs{em|)GI8q9D9C8W;2#Ath9&rCY6Psu-#4A?i$v)N0iu4#^c#)WAXk~)$?$6 zMVP1igXjOOZJX%m1ns24YaUSh$*+DK#%9Okyym{fI;pj{!LcTh-wJ-e5?ei><$-Vh zCwuu#+cy|hl+kJ787+QCOdsZx%w+PYEVa99!p@hs3 zCFjAVhAgJ52!7REo>Wu=GP*x_oVQT`NG{!|fr z(~0^e;n8S#ag&AD^sUj_ztnvf@rydp^*7ctfk#&0cd=ME?5Ui&@ei8sUM=NVte)}8 zDssyTai7W#+0u!WSH<&aEL`^nlxxX$x`f3eoKJEhJ_9wKwTDNbz)x82 zH-4Mv837e$`E8x|Zn4=s7)u^9y$&0;`&kNW!g&bOVEIJ)9S1kV9(Zfv>vn&y^0b*4 z!Wi7Tp`TtbcP~!~XZh~oJ7EQNKbEwX?|sg$O7O57YEVBIr3+_$hrRe(8qJ(WraO4_ zCbl+GRG;QMJFuqnEa?>9J()IN7S(Udc7G9@Hj>FAJ?=-IjYWWu_}~F8dDBXV-gG_N z_x=aBuJVwZsvZ{-9*CS&T{tGv|H$S7#!hAtO<`+5iWm-&kq6Zhk4Lj5``5TvIMHak z>}jXyxfPRIpu#tmEl#6>p;|Coj66y@;ryd~vbmBFw1g)=>rOTNTT*uaFzd`5=lOY{ z<{{Dzy9Eq|0o%#pI%^KQQ65p%-h{ypC+`nQ_+wfQr_8k>=dh-xj;PcItDCC!v=koM z`68jMiky?(_5Gw4?TY8Z;k2-7m}edu3TM@H^ZOL?n#q1!yLSQFPEXrK;8;s*7FT=r z2^r*Hc=bQ-cZ_`Zi4R-+zRM{BhwSeAqbRT(^V}^Sob{xWY$gN$3#T4*5&OD{K4o0- zCk))Bg@<^|DQ%8vWo~ONa_H?f_8HTw`|bRa)*WxK%}e;mah&-#)^n2O?$XMYV(?n` zU!v{PXgF|?QQqmM-C^e2T(&paH^XkXVgJ%H<56rRSl{O32kj4e@0y4JVa80&%+6*VF#f*Z0bA-e@83J@wy}8YLslUXm7aULAJhy z?7k4Q7L)3?IK&}W{Yn0R(9dP;?<8+KLkFS0bjrNwYw8LmJmX&d4tqydV-2s6-v^}J zgO*m1;&IlyiOxsBh&C|ceYi2mCv)M#a{Bqnr{R3ju)cM;Z+*d+=COcpc+(bF?DNdy zt_XAgzh&$DMgJnS(m?gM7z|0~Qy2KoHLSFdpKv-`7(aYPEUbZl)F!hLJaHXuuZHd0 z)s+(>J8+I9b;IJ324YV^b=1?e8)D9Q-&>-l@*`BAE`Cj=iTx_63F6elk$YwQud1=W zF8hBt@(N2BPD1^0&anT_Sl>-2Z+JkxI(=k{XErdBQV^HAH{m0k;6uIa!+yuRezbn~ zkzEZ|0Y9LwRaQLtRGgm=afZ2XQMMCyclp^_wnMEz=t4J>Nq!Zrt%fCAVaG9*oK1FH z`pBH`YW#H+z1@OQ1xTZ)S7Y(*OR;G!X$%z)!wE%ed0#lKB%EVEn$_NguFpj-tE>Kp z`z`bA4_H(YF?xZ>@+>sZNN2g(L=hI$5=wlpDsoPJ;;ee+Ki1HO9cDf=5;6=oc^+T; zPv&q8O8(DxcCdsMc=cEIQ|p@YO{@;?{gyp@y2ubmru-dit0q%AWp=E9eOF#dSr&U; z4X}dR>8th>{XoV311k^O!Lbo+rdK@1{0eceyL%3~{y!M)A~9zo#GB~3!N(`Dg|Emc zWF3F-=L*n#2(TsG6nq?`>Cvvzz{daLaLuZmhB=bo`pN{l-JCiA(87 zF#%$y#u(GlXCld6XZh!#$QJ&vQh&eIqQ&eroDVm}YYxr+0t+K@%bYl9A$;sv(ddfj z4biUZTKfj8=nAF6iKFcy-V5UWQ{;W0yVy4zdR=7yxx}CMwSR#avK*iJ8uEOmLhz23 zJYyYD7OU>@DfU#@T<;f*yp+S&E3>U?a+&(@@;#F4V1B}2?}hbY(>-x9Iqiq5$9VEx z_K**5WcH+kdc2wcg<06)B%$T}b8H-W5Ae>veCt1cd0u}24lns` zE}nfmHVe;bswZW{m;!3NMP;ltw5Xe$WHc_+O+IFYc-Q4RrQ6%i6ANJK=fDerJS!q%^LdqA#>u2!B z*LY?*$X^YfjN)ChT-5;r*YsC?UiK>fTmw?S>xxkEc}9GAL6#DByeQ8T!_I~MaNOWA zb6vl{^G348M(nGKmb~shq3&E9dS~N@SIPGrs|@4XkGMlY)|AuzpU}6e{(6B=mt~RR zjN`VR_o`m!@bq7_`5kz=Czd{CjC$NLRrMZ_>Kg6kcIVS9bQwz>$j?J9F6<|eN^YB( z7Rs@Z#-7`b#KJi>KVXg5)ZYtwN;uJ=qbGjhDPNG`Jg+rm*F~)|oB(-5Zu1{ZE6!$X zl6^@d3t91}TO!D9tRXL-sSUk4kZ4uoe>w2J4D!3ch=M*d8F9#~*G=%g`7|=Yo%{F+ zJCTea>oKyQwPdqaTPEOWVQ2APqEItE52r3vrJHn_&{+RsQ zk?@PqD(sVgOAI{6mR7R&&%C;eHZ9q8KQiCK`qNm2@vv1qPsB$;ZjeSQZ0DvdBt*gU zJmxr`*zdY9Qz1n)J?!21n6^}<%Qr}>G^;Ex%05pfIn{{M(^P5}bkoe>um|}~czuu^ z|7JY)0F++|ixy*A2S_|Y|FWxE6=y|dSxGf|t0vx-Vhd&B)_IT2EX4I=+MB{sa+xQQ z-#Z0xt1J9;ot7@*vpev`ldPzOb}h#zGRnI{?p@q?#vRg{s@)ync|8#&PeNyw(E~o+ zH5X~MeMzfE)*5O1*cjv$l5a&DHOa6#i!DK#MbyuR;!Wu|Tg|qbr;Z`{RbGwR=0UNxk$U%^X11 zK5dk&wp_7=G1E6Z=`r=*!p<8jDITVG=0NI{(4;a zEc`LxQ&pARIo3a2vUc()I~fmW^TXpsaJ>;}RMfxH*6SBfxoC|24Y=X^x6jTe>Umw|k(4_1wH`6kF)RCdzn4F~+}S10ieAfZyLQVqVpk z1A29sW$crQ>?4(PV&PvHOKQGd8b>OshIFrJANIR?R@*B;@H$ZU9X9nY1Z<{7AM)}~ zvFssGJM0DUIc~XBMma-0d!%~G5Zr30dfDiBT`Oy(ul#kC`qnUGz|Di(${$ z6;|MWgQ0Gfoh(&5Sxh?L^T99OvxRoGQ*-RDO7WrS&=m@Gibswc^33ym>3+Q|25ZAv zk>z;PH5k1J>sjLS^{QdNnj7`AQN^$QJo)!(((>3MYGvWW#xz8DQieaCSSy z+R0uIsnj0DSdOshA6V;GylAZY$Yh?jEk1K=gebp6Ty2c6PZTGQ#}=CD(VidlVZ}%J zdnNJqV>N{lurG|>jgw7KLs~cnVW(_Y}B^qqxEvrc7dv^)D zup zwc&d)X{ksy&G(kYvyB$)sCN8&y)cQc&}bm}G^3}Yd@Cl>{GmPJ9IkMZ>1BNGf2{Wp z|NjYrHo@BI`ml%GBBI-E(P_7AExfae{7%DzaLRCqxd(B$J!H5;@A}3W=V3CqNZ$YQ z$#7y|V7yWB?@u0)j0Ggf63>bvVU+!tdp*bk>X5^GdRL1-*W?j(^r(!U=JAs8!-Y}s zqNVSb^85ea=P#ZX>d#>xmup&e1!C^e#!YHT>&4x$E6F!LTT6TEXnZRiI|mW|rw;cO ze%Vv)tb@FwpImA-U2PUI7Q(m|Y9v|Z7boq?yx(5U$IR@>WPIQiV+h@$?J!#X3cFbe z0SPq4OB%G>5q{ug~B_Mq|1UyNH0WnDjFnql7dGQU?cQuk}@s2S7CV?AT@jezd5 zV&;DPM3y%?+JQapk#!Vc3AOb0RsCk0R$= zG*tk4d@GMTZ7xqZX(X&C`;o7N(*Q5ot$L?u8}_R|5Q}JWSgjo@i&wO~qWS3^`F%$` zqZ987^9z51CqF{#p=`1;{76=VU9LSJv6Vcs*xhop`LT3nkN@GmsqMR0EFRB3!5L;j z)fVijEQEc6_uYyO!t?ESYaHTm>?2S9K&7rV-r0ejPH@Mq*h|>Y?-_ny7fyxUHos?0 zd;I<@{MsTy59hUEm!q&o`!WwtgBey3K|W15D-JvsQN=cs{ueVb6BFl0Zbvpn{&jZk z1^bsxa%OEFdHZ_zTL*cIM-C-?q3-gtxqnf+{N=Z=S(e1{k)*^H=1#YF9&T0h1P?>g z_K>v-3A9qdo(0s-Mnbp*_jnkKibNiXgmnmKRCkWZ_owik?BeDiS}Ddp?-LVm$BM{>bDMvb z3r8wser$CXJW`}O%74r7ps+j15Lsm(b~I3nI?Cg6W2*aHGaU+dgaP&9))uOadGNW{ zVfQMil{sQ>$;bpeaF|s(!;M3ZVL>%mY&a_|nZJk8i9_zTQ{^uuWif=iCo;m`J-ZWn zo0m1#3cpVFkNe1M^e*P?ziBSkE0LunIMD3<7Up8Mii|KrZGstG#jJTgZ-qos8KWPdR=*l_;#NRk>Tx{uSJkuYpLb~;&|Fy#2_q5nBC>zMw3&l1Cl$?LRj zJUP`Mse-;)3iB?@*Yd;W+p(O+IV-Z4it^pkIP^1c<}JBICoLHxPOQY&H)w0f?GEF{ ztF&~qdkn)md-yz@wcO56bM@x2p1vEe$sn%@V}=*7$g2?kAJw}fWU-4(HuA-#Dq>+? z`&n2Tb|cA(L6yWo^U+?^?tZ6IMjH!v5|n&4h3{pjv9u(firqYgc|0x_CcwPEJ>#aH zs>zEEuhUvxb)&Fe`&AsF3je62n(-F9eM#0+2KF`Mr!#rZ1xTGmE%Pewxra@!g-e}e zNLf{J*Qm-gWNqbT7Bgi6wb;{a`OW}Wl=1sTSN+7+!ai!1@QV?m)iJRvU1YHF*$sH+ zHDh6C;&a#*izfM@%|fwwD4lgNvR;=}hw+H8-^piC=64dyrC)XA-+kjKK0phX;xx0} zV*%XTXY}PCweakbeCD>6G#XPPl125kx_Pa2RaI-4-Tf^5Egd;-kIBr5+avcS{u;Rm zUFt^mV9oE~83nZ?72Z|?eoQuQ`H$SRHY}P1fhI?$#PRzn_1Wv%zFnW%!j)v2|CW^v zCy@qbq|{(P4dhEhM4_+6)J?47e^^x#wp2jY9p+CzLNkxi4T#7a9L$x>kLT6JuHVL8s>$|M*l>lMaqIab zo)Z^mfA`YvWi}VQ?p|E=ehB^o-);-_d&r7Eq@MvWV+tHwDhruQTVvQ+bE5}O`c9~b zhRR4dxp6YCywElE#Rj_xyDA0|^G22?JRjL;>^6)~w06(@tb7{l$fw82vDS9d8)GH& zT7RGA(PiNJaIAHssC~+FMPGAkPN|V^H?y*@yr-*i->|ANoDMexO3lOp7J4^~dVEgT zZ^>Z7u3*V3FSp1l3f&%I2~~K6^9OPBFpB>-ZhlS{bJi2DxFVc=67q;}s!0Tj)Zkxr z)K@ZiZKm_jFy>Flu{$|8Cf_gvsvQgOLtEiQkil$aI6Lo3(!EK1xEk4~tfn`8P50X( zRy8?ZRcqv`=D5)`bqtj^){-7ZJV4jaL!DQA<8??^met(j|8(w@I-p5xcFKv^0%OHf zjTC>5t9>N$H4yph`_6lw_>vk!Z8rP9+4MExoD-*Ftw^?|`0<9yK^tSjZ(wB4vA3#P z@+S0pPb(V2=3ed-_L%>K{q^(2S$Z7C-^Rk_qvHB$So4>4q4$em1+l!eSYsmIrKXGd z7pBolI6!OfcY|r8V9siK_!f#S#|pn9{qAyz<}@%C@_o)@x?vm;+WuR1lRDnB z%q*-Fo2!pm_7)Fk%HB5W-3qudS;qFI_j~GzeFXGsIFD#38kEuNBC2=K^0|V%D+9^h z)TRV>_b)uSAhIOF!n=BOkBC|X{*>fPVQR}8o?D3se8^bPuF`f{{s?LgoCrKn^V43)QsIugQfPr5pL5qvBy92CcmmKes z@u@uI^|V$zsUKnV(u;(?aKPs%jxp%?oKtYRyw3em-89-_JchJ)?C$ z!pB+qJp<0Jk-Z+`FBxPy&udvtF|Mq;-GRz;*>HV`S%i%@pwF;_;!#pf<2iLnvpdbq z5eW~;QU%)7y`?nvj?<@{>b4u- znqr=2eYs)fln=~J>ld>N0zR_IxYt2`o4}4U;Dc9VgUmm#FNf;OudlJbVtrv@|@a4xNd~=XEGgZ9VLvuy7wG+Eth{G?nkI5lt45YSBF_Tpw;S}ui zqW4NU&v^OMc(Q2C!W;X>JECG!7T-_Jp|c*oFL&$@$LFcZb;r`*bH}#qzoYkB!s_;9 zI8{a)DlA*93ES-)gG<(-{E^U2TyEv>B9RN?!a?63VKluL#@tKXn1wTM!b!eSpPGfI zOtkOO5b@evrpW4q+L39-!AF?)^||&>*Yj!WSD$-+I0Lh)IU7!C;~n3y+x~p)W!ZBE za|ZT`Co9Cw#eNpyb@Tnc!tWcQ;0XG!1!YT!kR>qIu&eD$nBGT5suqd&SJXIis0rW4 zAHQMSrAYKj?0NF97UzFGXtXx_`8$@z_~R)#+--S8aW&xnINn*gUOqMN_j$r7ZJO=p zQwULyJwDDWuR)lfJYgoxnW#k*{QC`j`wp|;goXd)^P|w=ATKyz4E4G`MOf}bs$doM zv>Cs7AF_1kT_20m%}B8W4fL1yc83GaXr`XO!>(?{p++IroB;POv8LbkWD1OLsMldX z+UcUe=s51T)bAQ1*gHN6Gu6V#PD}Erh#fx&Rqqoss_>ey|64WQ@QV0Uk9Bv3zvF#p zFyb>iYDOXTR<>SC7M7;c#l?A*d2^piShpF+N_Oo8M)HgQ=iP zPMGyD6xxG1b;lPPiM;h7z^Bj%pJweH#p|#yd`&WKp>EvAxB5fPM$qF)*c8F7@5mvt z@yJT>w~wgrqt6qf&{vE&Y{jqU>EDmIS2#l>S%1#!*;z7jN?dHZ+DBV!?whL6w<3);@cwgJ{#_00 zJ{ryh6SKngFaz<5deTo*)1t8F=NhpyN#uFbtBOeaG&vR(8^Y;?P2-U&oUPW5r-$9R!iwoiDkH^I93OzV zVMHi~p&zA@U2zm$=AQG}=vW*yoS)N0`zL#EE?@e>m3uw;68sEjzx{}#?qtWaN#RTJ zZHM@7!zr?4J0{mI`7?N&NH?k>p9gg;S?W`DS%E zRs@^qWNd6BVewW;C_&3DNEBv5N%AY>{ly4Cc0nZ-T9Bmcph zQbfdXMo%u$KAgPpoa>6QyX#~g&J0~hR@;qLpG;XQMqPlfsUtsHi?`bxp)c@{u6q5v z7<-c)tl(cmdEhwFI6Ho|+)TENkUb%?O!OWzOI>HN&L&AM@98Np_QZD&B^sk^6**|ht-E50k(w|kNHkb29 zdDsm2@*_#-z$iZu!56~$UyZ|^^M6?VIh}srqvZ$G9e2a8B}Ut(ik+=sb2aN|^Z7sQ z<5q`Xc7Sz5;np&>;nf(!ENpoV1X~947qZoHB)8NIhc&dgp1sazwNq&~)Rqsh`13G( zr=R`MYZc8*ahETAcaEP9{>laO{*AqyawgVI^>s34-yd=|H8Z`1r?wMadikq^r-yZI zRgCuC@ApvSIUg&5-#=#l=Yuk$dyH#k#ocrJET6jQ1NNK9As2l{-q6A~JDMBOS?yvG zUcXQjtA)=zKtH8nMk7`2o}RWw%l~8*sf@=wVE*9KMvB7@#P=qQgHf%0`igubhx@o&prbDF?qTea;?sHY*ZuY30X2niM zt!pNFeC4T0MnGQWSDnoF3j3Cav%q<9UR-$9>YBqxj!{6?C`RC#xbJz?x%E?I0Rw*zs0 zkSsc-#;miuYb6NP5SwkP8r6|Rdx}?e#hjdwEC+lkg(<$PU)`WmOCI>7ztY3y2T42Z z#e0)y{K+rEdV_ubT?x@9(bOV$ayDq>eP@g8NO-{v+uLMV(zm{+&6#}hposCP`-F3@ z`}tXqZ{~qw#b89v$O^I>6=yjGV0;D^dLH5}7ENZz=E9Ep-?Pw7Vpurc@_twpP7cbW z#pT_r4h@%tKd;E1nt0WKLk;AIef4H24m}L^4X5!>NU{wHR`Y}$xJ4!rC6P_uAkRPb z;=HUUoXN8Q7L4~>I5TXnzAf_aL^c}Es_n-ITllOC6j_c(jK?F!u-#SKw%zAppW^G} zdD(qd_-m0?k7VI(*&(5jN`T$Or z2U~dBJI%y_-jLx#Uh`(W5_-`{!Fds4n;5>`9rnYtZJ636-jh$pTa}g6kQr4qBd)TM z{fbZ^7d@rb^N8s2k9_v8cure6?nzhK)Il+PwSMi!(5{G-ndmDo`z*kJ!-|V{`9wG? zJC9d>mQq#R4*RoIBj2z#Ae=8;U)3f%>)wxVea0Sp%T>0?@Q$1Hla)4V$wWr7{h8v@ zDp-F&gqq1-QXq65h3l`AmG@73*HjH5Py=m?ZURD!swIk_vF#jPMy5#KFD{_VOxZ^O<=Q()WRYv`a zyQEGisXxDq9^+zpQ{FHFS2gxetfYGN`(i_nSPlCLjC7BKtRS=T_2+2JzUbolA@#b$ zsxPzsJqXS>dE^E|w@#misUN%lr zJF?OE*Gl^jEby9a&rCD<{hkn+qlP!%jQX$KYr4ANLOJ1gzB`i+da3qxr;Sdqvi_wjIy3$1C7iv&*;6B8f4zWo({jnGRXCZ^4thJuO$`@VNFvYP%r4w zUbY{0N2?%)WTdmhSi!ff-#kSu=?Y)FOV?2x>8_mUUfL+=G@p|8msCHJ&2;kK7=9)@ z7h$_Yl0kapBv!mWy@*gmZtK+g$cyULuc)toK(0;U-Wz1x(0rISWIxy(5fLk18(rjk z>)_`?XZubg&r#~+?TppEpYT+qvpjl|2(ysqj1bGlil>`N?-%UzYiK)(uR5zDrL$I4 zS4jzx^D;jBJL%n&`#qA-&}d9u_VchF78iZXvzxF2`(eobTWo5|*4Qi~20ieN+SbN5 z@OnwjF%4dj$vU#4>@~A`#vN;cZ`$SZiV?W9DLwIpsj)+LyGnHZ^K$AZ=pj$aPVC_* zo4;Wk^SW{JE3v^T2Vx6Vh}T28rEK?GY-Jr}`gf>}G?f*x+e# zC+x2NooYtdp}7~XIfXC$Pei|APIx9e#N>($u*UNfqY^L1<98bMlz)8tbCNCQsrzBU zXb8E|ERg$EJw8aN$j+;po0BF|PUf;%#jL)3=`q>fqqtxeJnui!OKX1D3+n&f^mG^u z8;9l069X2&{FO9t2*=vz(~w)QfcWd-!Zh;^+L$+8mTl)zFMd4bhgccw7#~k*WIwG2 zX0&}|hC}Pv{V83%H!W5yWrcdvj#wpg%);*1rRex^vM)&w%|w!hEIFLR)efTd!;QO; z?*hnkM9#9$nAH*ICR|8aBY#=|KNgef7TCE$EL}-z`=Dt|H7Bca-0V2aEmBJt*~yj{ zCp;2aPReUVg?W&61yuhTkNK5_o>xcxlccxFPd9k&XT4kTsW7e|##Fb!h2g9>j5oaH z+RF6zgsd?aY<@%?BriM91OjQ{6sOVk*{xnx_ zzmsxLWKcpQV;{L9VHct9WK|B^EDne2h=P4_$PMzrG#1bg7g}|J#T`V5=V8kuK6m;F4W**vo%r#iSYR8RYm&A7VLS zwaP44jpr>LwW^{#xz0WS-CnYWgu z4u>t@#TnBy{A4)ke$30litpy0-o2QTYxa)H?1_9}Jhr4`_3r};! zXIR)Yo<7+XA=3H{ks- zOl%7l_B%wl1UL3+*(Qjvm8b8}-fy*b1_|}0zYp-m7FrwD{49VM>tMhy>dd><2=?JL z2lRY}%sT8Kv^+_=>piuL*V}CL z6HoZsvv!cyDfNNW@H4w!q?g~{##(=6ujAakIV*mRKA!W`{P8MA$TEh@Hm0dQOc85; z!++lsN0;)qVbIm6yXrn!49){dX?&8yb_<%D0^AVyZzxBFxp7qoe9 zyyxXvMLso=lA>P))r}V7pxvP8vkcw0CW%S3uop8)&8`cx#227XZTVXRS_o?n8nL^k zo=}c9GOGy1pxb#|ES%1flT}vWWiLR67hF+RCKC4Acm;PZrRsOn&-u8P!(8BuvYiBY z_(wdqIe}~5#s+WUYx`v;+hFAZeg6Y~B)I1taq+l(X`}Uxld!3A;?Gj`>77ow{@om$ zJ=pq>+Ho33Orz2ea_|SqD?N$qgB{h_RJ*Z+)c^Mnkpe^|VzDB{(H7ug`$V0FDj)vS%?U+%Gk z>@&tw=CPK&{4(tBwNvyMZkL`y2TD6@4u9`EMfNZS|2bHy|rq z&CLt`!`|-Faz#C_s-IEUZ{mGxvCu1!v681OCiwzl?d$TJ#7HBO$;*~@L!5Wb+ek5| z=BSxmr;JKxkcZiq1(x0M{j3R7_`@cd+g??cqa+kGeS=3NX-8VKAi`L~Zt-J-`E9B* zq)`kyl!JI-*NYasxdCoiNju7tL1}U?E5elH^Vvx)7F&Qx%*JrO<6Fl?o!#+VKUC(! z9P2cY`VyIiicbYRuAG=3Q;XOx_uj|S)3UW9DoQWu_lLMccT(xX;^yK4t6=;Hxp8Nl zpp~CGB1+hOsudJyi3J2^@`T@uVq-bHez&@Czh2&wtA>&PM~#~H74_%Bj#=b2+x@qS z`#VT)mb>)u+&1pmmp1p|=9MEoj9GR!_pUqsT!8KVW^ezW)R@0XS;*&BiH$ROdu39) zOg6`$F|F7p%TAYYt=2X?becBj`T}`3r2@ z2k}zG({PH$9}xLFdLIYDM!?;GsqOjYWT^Hxw0#((C<76iv6zn`LKuq(vm*-8WJY(s z&ZK`>QIhXwP2m^(?&-g)gB_eK!&C0s0J2YSFQbRx#6qU1UQpiE}0ma zfiLb;e{-_6vET}k{_2c<%?BQZmyfq%c`}YL$NZYv_~r=n#d@3FI0|}9cF%!oj{3NR0eT3Z=IMLnUgyo{v>08AQwDRbM8N-6%5ZArjcBjVFC) zlw=O>WFE8MyRq%o&^tHT9uZe(iAv+)(pE9@1m=637dx*HYA>hfy|Cc~d=0+-u>OU$ z8rijYj@a}nEoT$8bGXM4j37S?Uq~{yaQG~IekU1sVM9e|J|p&)0*NxQ@)!6?FS^-6 zX8TF*Z#$zE#?#+1pZL|tt%PbuTnc&J%O(q$Q<~j8y7X$BdF1SQBA>{d-l4lkNF$N- zQ@hJut05A3%fsaGAmn+7EGzM@W}g2Ze|ZH)1s49iY$sq<39TsQ)r=L6;d5bS=%X0P zL-y53BlcXt4V*RZB5vYLNHsq_5nZ+`YK z3_BsmI?TSq8jK7qJqNjmIC=?lz0O`Q8;kq{7s|}rpJNyG`18B+pGug2ZB{c>FDJ92 zY5Fpqm4y8y8_PSwy1f}P@{wBJF&PY;Vj zB}LS?#QazFB%jJ-Hn??1Jl`aO&&O?MY1=1!{C!&Qh86XKoo#t~ID315cP7O7*Ji&h z@!n*(+8vI*g$vchcmfCQ$p3dhi@S1#2U%ZOY4N8xG6-vZi=7l#54ow@aVB`!8=P%E`6?K? z+kA>E&I-;Qc|KAhQr6t-@^<~M5lL%L^&-ylZe%~I{^m)BeQ%G;%i57`CRP}BhRtZ*7KK2M*f`iVkBz zok;N`Z61V!E|768H9oaecD|cmhSe&8eUFqsO~a7FeiTEYZfCu0se;``4)uxHHw}C2 zE5g;Hr+eKsA3v`}7d?3EKr#+zVD|KPn2EfB?l#Lpc9ZzmKKov)oKDNOJA3Z~Z1!zF zQG*54f)hw)S^b*jr+QIPe`d9!?Qn$xfEVGmfRcc}g4q#AUC#_Z@9Z zqs~x9RA@{eVf|VcmfDK9y~HZ(i=l1A(<=0p#rS{J9aG6Y!-+rDN$o?{UEg;Cx4gq< z!ydeu#FTgV`iJiJA_?#0T^;yjIdMK8HgL>%+~QcFl%pgc z@#iV-x{BYdfflPp+L>ZUYo1bFD;lxoRxI=#uZsLW?Cp7ow!&%8{V|2G=ko`6%scAI zok{c)ETlD#(O8b~65d`cR?){njSlK*vJH{X-(DVg(0__5O?+KNCeVCNu+(%pMux6>AE zHq4=}%)iU3BEG@$bNl;$Jh=nhtL=YP4L0#N?6{2S{YDD2^kg`D=%{~nN#Sifl{PmT z+{E0iSL8!^%sbES^{n-o<zNaqtN_83?jQ+B$>}0!c=cU?11)b<*?&e ze^}S>D~;~Jaf~3QIAz&*A{(#+Wf9fOwei}{!^Q?T^Q&p}Hixwz#hjmDJ)K4F6~;?8 z;cC<586guX#3KJNf;fp+y>GPpE%Vh%SxJ$WKjtH+dVIBmmcQZkj?A6+&7Gpy4JJ0z9TtNg65ILVdJ;-X&FvFf*IAe^sO%D396 zM2wY-w1E(1d2(quP?;B0!yDdY^PlR~XZ&tB4fLkBUaktKU(Dncp+eCo?i-!r=rMyF zzZYS4`((5BZG$I!++({>_d}m3Oesloxv<30@89We6DB%GrZQH&@)NoZqk$uQx(JW| zReQ{jh6hLZ{{P5spL<<}Lnl1vvU?X)zbY%M34Hifo?jlLOwX3n!J0qW?;hVj#2(Um zzczg7?~|~9QauRqguHf>mc2=aIrS+AY%S>tc3y~A$wH-UH7olO8ijME&qBN~yMLnf zZVjxq`8IZ39`}))eGPf<6W!L4MjO#8?B(&Awbl2rj}*InCKxM72P^8ai-R(kT%P`{ zOumsU_A?xFtDp0@>|UdE!^E{0d0{#>a6!-S@VIo=#D%@S60P^hYp1qKT3$h3SAf+1 zgZZ1?_iH#ZhxWUZTz$yg40_cxcOt9(y0;sXSP@&JyaPQ55)Fb5x!q8cPv(oU5{pQdstH{94MSj`=(r?F*fihCUb|?9yaIVsJ4cg zZO3RooVYyDxBA8_y-V293RtlMa_%IVi(Ux{Z<=vY4BvP# zUhB?b9!5s>w^|s}G%@`$E}sxdjNIj$|9RcUDX$xsOXSbV=JzBUt#}IKeAbA?QzCX5 zXMViq1cy4-!BtZ;4*S|XEA~H$3&iY4lR9!oY|m(ATY<<;eBqAT^I7bCugHE(E^*oa z$36E)xUn&zr1?6}o1rDfR1Z&j z(A~E4mXV}AgY}LQqxIsEH@cQ(b$%JG=T@u?@Y>m|roQQWMi|Fv0a*!iN5 z@3+yqM*7_t_iHaF>MpwU5Ocz=t#6P`H`v+1r{SFHC7!;L^~?~9XR5f*^6p%j^di@- z5Vwx<)$h&f=u5UOaf872?b@Nm&D`NNuL2lFIH~?P>-i6B%8fgeW|6HuaWcmJi6^`& z$FHL2WnEPg`iH$b0;@>CQ0}9VC-tok+mdH{{*zuA)OWLJWf7m`()zn{t1a@}(>V8Y zm`D%VT^)=f3)Y%mmX@6k(|N)jIYX%WgiP0{G3`DqlemX(+~S$xbp&#Uom#$zhpS-l zRz7f&&X2*|G`LM@V+x;L2TP~&NTd?t8?9uKIG&YIt zP1D;kp4h~A&uu6>i6x8{lQ)UAH89K{wJVvXPte#GbX=Y6vd9L*Jc}RT`;R!tUQ96T z8g^2=4_v6U9`=Vqvq*IsRxypa^gQev`J#HjL++iCr9^l|Ha7IUI$L-7 zc6)KWzE@!wcv$aO#K+t683Vr{W}bzsVb_4wbUuxyzk`n}$l_!EJJ7gKciL>?^Y>`G z8=VcMhdG$b61XtI{XQqtMKJOob&#B-nUz2MkDm@#w`&1&2a?hOJQh=POmWh<7*l5vs&KyP;52?XfxN?BY5OsZaP>ydeT1#-CZQU#n`%(; zakzR%j0$U8J|?N@zEvV}Az`ukTj!kplR5D{XD~e-$&{GKDOLYDKXjw{5R=S#Z^B<5 zRTp}ItTLJJbeEmoLyBc-tOd!39Z-AF(g5|>4(5q{Xbg2c#51Dc^PPNsv-i(y_Yvcu zVHe{5YAWx$x~113*Un^?8LNd@9QV7l?nI)ghbX)I;FoO_A$E z-`c9$^Z(~O%v1U43kTZE-0GM!R$R?ASuOGFlrLhRrF$dvCRs7)ql-i?~u-ngXS{6oA z{}my_USj7ULpBvLtc2DEu#(AY4}sro;fq^X!8-h986+R)y4F0a18Yx}H`~yYgQ)dEM`4@RSYgY?W%jW-VC73a5MKY&QBe z=C#$GPpgimz?hqQb`IMJHN6XRxzlRh%zHKm46RUe71wC50)mp(!uLYNXUM2clW*X)BUT$``7bOWp$ug02=yTJ z&Y+5KEwnmsYgSW*yz{B}73A@`#gP}0oD$o)wk*Q5jK^cy`{l4GC`b>uN70Rd4na_k_kK}vnmFI3bDSl7=trm zT)%{^hqGKpVYnT|pRS_CDEjWL4NcfxXVx`Arn-e4-oQ34iYY&{#$6CU?6^Fi1uoLo zsXiYK4Z}GCBjcYHfv3-?8a{yory}ocZ00GfB!`F{_U>Cs-#@6n{D%j|M6~lf;FSE~ zA-bF3`hUcqEb5Dy@wdIIj!jv_MREya<>OiK711nY_3NR<5z?PeKRx61!+Yr=LZ651 zUAjP=o6bkti@PDee3>kYdp(4W6*o>?oE;W3wo@CM{*c6ml0(>oaVqawF7LTu2DF*l zG*OMb!rY;Tys{IYsz*Ns@Yx61`7pHuEBQha*Ikq;*khMB*VB>@wYigM z+*?n_$mHhnuV3N8HSGQd#_%6DAESpy?ZsEpXwog!i3J#5H~!axre}*CY0M-j<+Bp1 zy}9gFmBotNC+*)KPPl$W7V|XS{7oB+@bF1AHkdX#dO}!bGD5qDk;X_kF_q1&)W)@R zJ3}iz*UxD%W*CoZDS9^%bIguc@hMHq)x@0gH2ws3nOAHKBjTCZbb5NpE?$=AJ7K@j zCOBj_R^3rlsLyX3c-3SD1z2sEX?zjJEanHZSn&FkcItrR`Q$*%tAcO*DgW87M`31j z9p9+w`~P7#3$<-HIfZ@wy2?yHfcq`!wXgntOA@)*OEv$7{jbybR@kvSRKPOG*vC7Y zp^cpAvUyqE-6PBty-1#WRUGQcdosx4{8exfo>J?mE~>P_-PfwA zU8j!%IB*&9=rs|hF}p5fw$^oeJ_@z};;Glj`!YHI>RWp;{+*t;p1!wv9b{KwRC|Z~ z`a8UEo}4`Fp1Y9uhH?6>WIxl`UlZfe1zGA-S~(Ldtt3B~WQ=2}7#L;{KW;E;Qv#lS5|8iK)y1OF>VO?CzEgqz8pj_+Tb(hd7If8AU*0CW z@_aL_77Eq!H1KM@QGuxtf1x`Xv4^mY^girrRoN@-=^Ju`MmR?;4C+aDE8t#X57>^_ z=Qs%ZISGxBb@UXE`@qlcYUKls-}H@R=mcDDig>@k`vblAA?DSa$IcP`zm{M0B;hI~ z-B6x9#hoY14L-u+LUbquP4dFftZ?EGPBRf|b{EOIVP%7PL11Txw0*BU^BXmfRkRUS zG#w+So3QYV%zc|`zgeCfAftl^4+x5~|Qv z6l=I0JBhJZWyixslKmn?hRAxH=BOP1Z_MLI`QT?H^gdbUhjH83!4Q_)1ed7I_g|9} zg!vp3w5o%av{kWbYkpb}7(JMMv|}f&{4A0gY}f9&^u3CuZS&U&zIxH?f6!?^^!XL{ zTgNMx@Pciu{%0werRs-X;(%z`*MKzo=*l!Z1^`!XO z4lkU>p1)?r^NdqXmXEI%g}0LODgJO=Oux?h5+l|IM+TUc_XBNQR5b`Y*Iu!*XrGLK zgHfo7X6(LYRH~Advvox7n(kX(wp2}q@wR)nz$=Hc?->|Km@C~7&JFgm+X4>zJ}d1g zcWuXJ8~AQDmYAQd#mMqM5iG`@9>W{#N=gIW;+cF+-usMigsa=&;UD>{1MXPE7(wO) zyHi?gSzi_TOIDW(%czg_h80UQ_*Gr;KCS#?nHt_GRptrC!NYvBT`=$u@hORYrRNi6 zc}rXJvC|Y^N~>;BATm&|TNx8>!0(&#zrbgP@b+f>C!k~so_8Cg2s7Ku%XFU9+B~Fj zBV}fs=jDM2m0;Y9uI(UGO3`Z6-0rX&=6+dUQP>@-_1WQ13OU?o6#ohSU05Wz>}P~N z*T#|S!^COq?Jx4m&eOx(w~IdeTfUV=9Jzr@EEY8fu*H5N+7OmHm0p%&EZ_RZ53c%A z?A^%r!)`lazrycaI|eFram`3px`9_57g5it;B0Vx7fhoKpIFNi&hvn6>^O|IZ0DC@ z)nDLh=UDb#xRVTru8GPK^@p3{?GNgO^F3v&pA-JNgDr)1awX$jH0-~BpX@B^vlH%h z1s^QVZl=@Qm&R77%8RCwqRhaovdc?}0yliUAJt9eekR+86wt221)C z8(hQ663u@v?3G{jBkUts8Nxm-8*X4lLwhX_HJirbcG$BxNtAik_`;jCm5gisY(CE! z_IuVH|6o6b#G!g#ukif>^i-OZdcnl*Do!twNeO%_>}|IP7GIRL-IYI`<;{Pnpxl*r z<)rJ}zI{a{Ah8$;*ofkcOOK~BMMf53jH9|cf9v3elVF& zmc-I_&`)Fe!u`fSa^k^N@Y@#fXd}c=5f{s`sP-&ys@VfG)KBL^;JNCWqv7-fb1!Dv zt8ufjm^0=Gq>dDfS9Nbe=Bwtc+%-!g4QxJ%nS29PW{aG2JpEI(fe(%KeylbS&f4e$ z=exqs-sI7mJ-jWt)r1%|AXk_ncb|8%>T@!rIK}?LOyF>?%URfvS#--{-DTQ@zPvB2 zWSL0Y(=fKMOZ#ZicOtzvH+2h`pds$N!5ug7_pjqP z5zebW#0D<$p;PgSb_(oxP`oItg~j3Av+OnO0$NrSXo?lg(xY$!?jT4TPQvR7mBT*m zVXU&KpDGYN%vmmgX@}k6&$!UqZ5pdf3T3;grzN;yfd)+z+_YiRX;Lu)l%{qoGWg z(Kb@whC-4hkaPu>u%2{R`**CXI=aI&5<85K9PpGKp0>pGEBV7ghty;hdIl zG5Q8PB%DpTlbrW>@?n0JmQ6Rr2q#;K@SPgp0d{y$B%K5)U&pZv<8|2+>S%k|leUOH zhj^LOtF9+^*0#a?awQoY)|yN4k(x{He~APSlH>op_KVPaMTehcGfVmBBvPG@)AfW^ zAL>&d-yNx6VdmXrRuWD&`wZim%4&K;u1@&&Sf7TOsGG@Y4XLkUK|6Uzh!4M##DcgE zD!A8svLWAI;J&m!+>$nHC7;BVFh=w@7ip;hIuDdRRv=&x_+!Bs$ZSS_Bo%Z#CGBo zpica7qUQrK@aZHSCnk;&gNKT}6GVqO-rop$w|R92Kbx*fIGsg~=l9ci{9eER6V)%X z$|GtaOR@W&tn?`yJ@%oFI>|oFJe6-2O6g==jU)P8CT=@%QAsf`Nm-v4r24b%| zGKy0)uOyn0-){aFV*~@_nJ?mB<*>;u<}-CLKj4|vg^8BT6E2C!j+)VFV;l?NOyN~6QlT;R}TJ!c#Vy89FrPxkX*`A|;AtVqyDfS=RDhkzy zH<{&dnPE?9m4|9Z1RAjEMSQ3dFL_oZAEH`vHb(g67jf?9yL9$}s_A)aN={hWH%!J6 znvGeCt#P}j$gvMRd6Qkl8ES_;-<7PuF5_bdaJtV({9|~z1e+a18a+gc-rDt;88Aih z>PPT{b~N5aYx^1dinG7F@Y-1S_!fkZ^}q|EPg$b&%H>tvB!To-q%v~aDaSmrCe?&>AgUr*^FgZrjIx1WxjgB7FfQ>J1s@9 z0ysjPihMpX&~?+PrZyHm+G|&9IqQq8eV$(RCxrw?)`Cx_gA$3vm*%WaHIv&edWom4 zi0@+kMq6>?33E~!YE2jRxymd1-DNqx`W}5A(uS+ro+A36!y7JY?^S5AEg6O41fL6H zOq>Oi8GDVLh|06V4lKKe-wmKZVg3^PncI!iKC+*xpB&NGbE$8$*bl{-&Gfv=V}uA^ z7DKw1WIOowXu5xbe?(TYgKh5@vod1^C2)sqGQ-_|rfEe_T;F&%;%rwi34OVBl+P-Hnb+``QOUxerD@`dgMu&Eq2V6#qHn+abEHP zzkjtJCu7QOesWnOl-C}5w;TJd=v4Fi#)8YG+-01&kn!JwDb2ilqjBF9iWTrn^7 zqIu0%ooD!8n$}*=zJS>=m4J9#pubO}C|N^Vn+);XS$36l>$&!DE&rZN583 z9%mp#MRyI&In~4Z!OpBLR`Law7tyo9`ty!{_aNzlPQCb)z4o*R!sGU7>|&3ksrc#& zmi;A8lFCB!i*qILx7e+@D!i`)7a#O@e%da^vg_eukBY!XXJOKKlAR2X4w3pv@pnHR zEfdWb$$FM)MeJj;1OIsse>lwMZo!Spkbf;qv4@f69=K^&Ue}#1jDdmgiZesqu`vuN z2VEb-ykm6iL-scVa@J%wxr{bs^8I^guZcV(PTI_Y#pm_e%5?fPPmX^p3VU6-8U;@|amHCPq&8il`@8(!biCUSIQ>uX?BT6qi}j zFSx?>GQzAfo>Q!JGhg~xKYwGT|FPnK$si{WDG6H(LV;UULt?MZ^DrgYV4MN}9y^V( zj4^oCtG?SuM2}ted$8kJL$Vl`h&e33c=ny^?ev}X;(g4ATP@O0cF&R6%WSA%ej0rG zhrMs{n1U;`*P~eDb%w7OWgC^mwdKK>;<@XRCwE%uka+e0a`8#xZ z$EQb-P3+(iC$yeqdw=r7qDEi4(8%*LggQQ3UgXQi8z1of7Cf*C^GUw&_``- zqngCWSbog7-sS#l^|K9|NNC-1nba^6h%?C>nnPO8^KxD-jmI}7$*8-C9Rjd%@*orRhl~PJ_NtA7bC3Sc!6k9|m@2VcD_b|0+IrnH0|Ro?X0Wt4O^b zTbx6GF^g#{)QgkMU-I(;B!8M!H1=*qTBz=|X7Ye~UM(cn$BtMP$@p%_pT`Kor9^Qv zfU2t`H#WLbPJGE|G$xbJ+$;)R$IIg+p*Xj+u%GLU&|FMhvo8B=Vn*WE#5i1GMdD%S z9Hfw_!z1NdBcGkmw?EfWR*@x6S z`$k9B(cAY%i@0{yB%Q|CVJAHrE+<+B|F*!B9j?C#i{Hu?KNs`)JiHOtC3NWd>_(%o}6vnhCH9;PfuxoTQT%e7Ssx3iPOtF>TS#)87k7o zX!+B8w>d^rl}A13vvrM3wiT&kw%RRf>3Lz<&Eo$-5pyeSIZh9;A7q>nHir$a;w`bO zTU021pr3;*^pNO$QgqlSrp|&`OJLAuy_y4aoXeqhn%~vWLHBDsq&%N^MqQvGf4EJ{ z|A#wf)0^0Bu((~6o4b2oBdIf3$m@{#ZX-X}G%vk{2x0SW-NC^;ySB=qB=B~*3N2a2~nboi2txG_A#DV-+YDY zYV^0tvNp-H$GGZPIo$gy3U+9w^=HZ9br>~DbeRIb?T{o=#mHe>m@^80e2rzcg?IyT z%;~Uc1||?YXj?5Kdszz=SNnT~D82_j-i1fZ#)?L;%#UR=CCwKoo3bB=*bURRSr@X^ znwfWTi>a`5IxR-Fw4Mg{>EB^I_iKOef_YQieSmAfXx>5%`AuQk&naighH0G_nNqZ| z810u~5BJMxYC@+tB`MY)=7B`%*~nJ4?WL^YM-~*P*RD%eV@B%tZ1PwodTn5%u}8{a zf6wx2?CQ4y0v^htVXC@YP9Iw#^M zu}AiOn0TDaa#Eg^15YX}i@C@LUlKd>@!BldWl0%xDbE_g(%H#1$u-6D#oB%gk84No z)6G?hogF9o=^`$*aId>~;CU@xt{yjC<#iceaL9em^TOC4{P(0^ZB?gO?b&wLzn7Fh zf)eAsHU%c^@!7QUj}!25JOeomo#mGeS=1I0?WoLV1IE-2yZ%q48AU6NjM;P- zv+Q94UF;);Cw!$pS>!fdaeyssv}nr4G+pc$aKAZ+SL9*G+3GKBIqZ2P$@XAP-9_YP zJh(imv=GnQ;5sFt$v1SpPh8)n4zv;9S?<1zv4$;Ly3Omchtx6859`q+avA_NUl*aK zv5U>D;w@Ix1`Ft*e^JfpjKN^@DwtW*JjfdEA)R)<8>8OSlW}pI-#cN?8dmp<2$`RL zilpfb%ZB*<4piCY8sCxjdEYo)SkerEkfW@D{ zbJJts6|utc?DGdQu4|O%ZLw;QIh{pPewUeU!dC{fkJ_}A9+n@_r?=@e_8N{ghn?`N zq2kFaG}wSW7xZ^Q(WE?iR1?ALsy#em9r+7zu9Ny&TM?+4h}B-??`Lm`)>cGT!2#}b zy_&ErW`!?N6@DMCMqMmc_~uXUSGI@WuI06Fk>?j8Pa!$nbC6<^xHOZUyo@o%cz0P= zP?yyVAhE8b^br4u-Ega5XJuvU&HWYg{-=8kC6^b-xhfgw=b1P9^tY-+o5Zm1Rrmj4 zC*ShD{eDOz^Kjh$TF}7nSUVnjbv~!n!3F9;%68;F(DUKiH&LWqua7IeHr6L& z)=)`UnO|%v3QMyj@#X@1+s@~IVCS)~*?GSArB;6>D(=zp*gNw#I2LQ6?k2T|aG(Mz zdjGQPh(Eu;)4#R2l&s`&EVjN(z77A2lgKxF^ka*?MT!yHFhB)kyh`jiR(Kyo{FaPn zyUTnimO=g58ZI_eDaA}xHq_SL{?n3EBzTfXY!tCNz~v4sY7UN*Fl(cXHdRkDfu{7- zNWYuXV5}`}LVuO?^&WjHsJap76P$zZM<7t_nXp>+vOo(~cs896cV%U-z`(cIl>Nm# znzGtEy?Q+qErofuWo56*&YNj(Ep57&-`9m&1I3N0+7`QSbQY)UYh7uN%5s~>X79uvOI_*f zW!^s07)2Km;ThOGRu6-5#(thNXn(nwGKX!<_Lxi}!##RqDt+joC%f*1OEnkeYp~ z4YXgDCT{058T@uq0Sj&{^QjAko@cq;;7*IAeZK6kKAzWvEoEf0MclW6#~VI5Pmf~f zk1ttGoMyiU=NJL6sSQ7ug}r@H7cZ|#fVbu=X_!8i=of( zjbE|nvT73b%~3CFG$gB40;*QYFYm!2}III%W2uKo|NJjp&z`uz(H@2BC-$v6-( z`&kJ4ytZ~D|8edVd!iin?X)TV?77qn%Xxvn4e|eM{g}(=R_Vt^vLA)BK26&%=*Mhx z753}dB6&gyGM=L*aksTrr=9Y1GVz=7o;n!!JTc({9LNWE^3ha2_HqsKZWmKxyri0+ z3yJGf7t3Z>Ij`iq#2&frABic(^!C|<>Lz1^vD5S7%-4c_Ql29i?dN-i1GPvWgcHclQ`LM zs?XKsrMYBx*W)$CNq2}=u7@e_y51UCuwNXH8PzS>UI$vTGa3Bd&yxow=cz5XUgI9; zzhq3TbJELui2;d^{iKm)7ILMhlWZpTFK^B+Cc@YE+4e`;{EnYhEb}reyHh?_GUYe> z82!dd|5WcfAXctY!(RpSCbQ7S#+@JYYEOvSjCGW8t%qP{J+Z1D8*0SU>zO4`iKXUr zm!DLp4wCN=$u(xf*vB$ny$;^3u00nv9Eh} zwsf$XH`~AW_vB0}rGg zOqipKv(D9qgIaijFJvYEhmtkqx+I^^oxi|kUc_)}s(d_U?qdsMTKBp`J~@185vw|W z@w7e;<9W06ZJKsYWck}~5JjF-#2Y35%Ly4-FuCH}NLcrqpC*g+FsT%9#|x@o`_wm%dE_RQO1$q0_}_^K2OIuXU3nqQdYPtFrfDqBO**3< z;fz!>-}c$7U=L<`#5xJ{(q*s{R4@ysIguEW+AdMRe2v0tUG~j`nRUp!4csWr?<4;9 zg0B_Hpt>tICD%A7XtZme_j&`KH-Zg*M&s#H#)^kC(lkn0Z{LPh;@1=-N>d<2Si)3! z!Z0yy5~qb z8iFx}23xVk@3b~u%KOGE7rXx5Bsj~vHH~{`HhTA4BDa;Ssflz@x-{SEAa+fGD4$>> zY2CjhyKMm(hl=SjpQ{!b)t3L(P~WN|^Nd=3Gc$EstF(87{m+rLaWSa;y9(?H`SA(6 z?i{hp$Cs&RjP6{4ZD;B33R}*c(#fpn_C`2fQn8rmvDl1?k0AC@yX>X49{qMF{FGLe z%ac;o>h?m$H}V?C$YtlgeCA4LG174Y1NqEY?kadc#%#CV=3DeIcJdN-66co`kvqit zn(Ns?%$-lQN-#J@aO#u#xfyP)hI0p4{XXcplSjnPu*>{Cz_WpT<1Mj2#=n=6?GTTi z{u)8U>t(0MAWc-=Pw|=0ljv1}w{(V7i(o^H(+~8h0Y7rVrh-;YkM!3KtTAfk^V$9< zEb1K^?g25L;y2;bv6t97@w&TfR>pAelWA2<=4j1nt_7a_r1yGa8*h1MvA^F@*O~`G z-*>mD{BIUTf77NTEOMXTT%*^lboP(v{YNsATqm*@!Yvvad1y(a5xHaS^~3Nw_V&T_Z>MI>M?xThse?XZ1TyFOJ=5?~%>d(~^EXd!)YggK6Ewhet%9qCBOjIGbQ; zu@deS4*n-Ey9_t7tB3ys7rw!Nu8OgDq1VF{4d4F~=RT-@a^C0e6y<8d^D@a9ap}eUUs?1i_sS)6t)}IV z(f(_6_ca?lrXsu+>v(}&3y|<}Tr1}B48rx=u!%9y;Z*865%Ttw4}D_?3H5UCTkNm3 z530p^Pg!Jyv6`@%`4Z2w`{C-slU=`$N|~9dGM)Ols_bL znxWWI7XSY{hAbne&qS4&jUBrt#;(2@v@BLaorN*!SwJo_&qV7{RW9zG+qIw+|17GO zRh0I^4qC9z*P(qopG(O1N7|p^{?rN9qVGu5fdx?^EF&k5b0=o#(KuEd`-KnS@3Gs> zNys=4Vzv>Zi^Hh&M&f=<^zm@IC;b%VEq6kx$8pM$_-(A<-U2h<*T;8M(WZI4E>oQD zUW?>7BcV{!WPVcsu0P~zabn&Lr15j2oH4Cijg8%DE=66q7iZG7Fy{4?eQ~SFV(NJ{ zPW7&)0$0|^T2=Vhh!mUQwtZn(oE|d7HT%-n3+i=4#G*LsY8ejKpGS97@#u|pyba^d zsqz)FL-BR8^AjvGPN^?QZe{p)VBKxl*=_8)0#B*M5AG-1vg8~m*!O@wQ^drN;Kwc~ zuo2>|GgEwuI9<)RzEf|Q#}i;bsh3X~YJbwD&i0;SKlkyX_d@F@KTR{-JcUnEil=;( zlH19kbFEmvo?p(x-^R;L`m?Ow{A~orFwtvH_u;E=<9uVpyk#sc#xmB4*mG1=-lXA4 z_Gwzd+IAV)SPzH$K&Nu-J1-H)pcAR*<=yu4w zy6|*)1y1*fwfSxM@K7yyEy-p6<+uN1dw22sYM5utG0V=o6)P^Fz>H<;0-*nkZ%`C z)|pBruVn>+zh0w{6>M}roovQgV~^aCG&6$6#`{F97dhfnx1_|VO?7-MMnH3^coe0% z*ikTctZL{=`Jvunx%FG_-d}bz5n7Fst4uWNvQay}60gs(rE9D?YKdQC_nTqa99$*h zW?$A@n@z^}MGf`dN*-0%VI9%t0iGT;kc!sQo~xIZcy7VmelRjbnv9eANhI#n$E*BO2CowEVB$YS&qaT zd9Fp+Wt=imf#t;c@e#oq!t_?+L}z@rkJvHHm8WB!&tO&6#pKw9vY~6&V?7UxMtRvt zLiQbd9A>f-=N~!RA-UFfq_&DY`p`iK{p<;KhC!~WdOHewcH>hkd3aO-miWdvjC3Lv zG}@j<-ElJ2LF>kDH)@91$Gk0-F)`gH#^#?~JXh#h-cyYG0{Uk&rt`8fcm zPvLv#$@Yv|)t_wXx8(1VxJO;`ewh_d((@Pezns25AhtiEKacS1@;oxm62BFvjML>~ zHF=yjnF|lEt9sEG_k2LEd?WApL1fy=lRp&e7UAad^Gy}~y%^hm zXtPw_)ScGv)4#0RlrcGiy+IxL6m+;-XtohgZOf`h!?0Aj=t2zhGNe5xS9;H^;i$`XWY4LIsrG1ZYroce`C1u~Yyc~H zpDpZX8*%1XZrGX|juaO$OOnSOY_&87Q3@L?MoSgd5E@|(w`uR+Ec6&p`59|DBRBcm z4t2tWMK5<-0W1Wp9-{ zuaGj$JhG$a#ANbw8h1Di%g^Dq-==Ara$YWchZ*s|8W&uwHut9aXPwN+Xa@BgtEHEL zx`pVpwnuA^?hr242<0=9bP4mhpyHS+&Ru~gKZ=Um^?DC9+sA{>kxsn3Ulq!lEAK92 z*-J5z*g1EYs>U$SV#Z~xTzS?toAL5ned7bz*a|+CpoM#7$aPdhTC%t2eYOIx{L>tO zosj1zHGwLmy_LTdmm78S{rMuu8tt9UrY86uYZ&sVipKthUHvrR$7NvW-H z6cYCd@G0{p4KIve3kEj??=Q#<=>D4QH2&b*HMzQ%5AiYbL) zT}}4Y$@gO1qNTnR@u(>N#AzQfC!!H=Z=|oCSneQJ^ax)$N+U5!pURuB(8mFowq1L_ z!ACyFW8cw(S-9Ck>}(W2e}%4k^626E7JD>orlWy=$Jq}(Xl)|BE%Lc>JaW2R?PI>M z1={U`7#a1v2>Z?sYi`9t3u{wR_7ZD2%0up|988u1uS!%c96zaZi& z_PC7Ktz&PoJH{@5$Gn99!GK&c3a3Nx>e#P6#?G2T>Hn_`9UG1$8Ycm9A}KEpBsf$jZt^&<8uw*c4gX+*|W9jxQ+j7sfgs(qN~vKM`KKXyGIFf zDC7TFn^b_6q$lee$vPJl$qeCdRyjz6-5p}3d+B#Sb`i5;7h@2USaWxA{dxW~LS%oR z<*yd&x8f3eM4zRi&;s>}57@YIZ9bBnm6U*bPhljjU9CDVt;BD-@QAs5aHafc1FjO+ zU&@x2s$=}i*UO7DMaZozS&h=p_h9ZC7<`OH9D=#aXm>f8zNasPy#IvPqe6Kdt2PT5 zE*H`NVq{&3^d5vhwY>iV>C|C0`NZhEFoZjB$Q$@zZWWU|(5HnbEY z1C@+@JSvB(D*or@r&*Hr@qt)+j1T{$rPrWrY1c06u2)6KEttr1cpoQW+yJ8=W^Mg2 z%4u5kicI%G_IQIkI7N=MVmH0EcH*TyJ@*~k_XMN{}o36W-pX=Ft?d#cm-$rNItfTWi57(H)!!yp7|C#u)d#^rioQ= zc`PKYIlOF!{?5|Uv7YzmN3W7)tP(HJCrjyFS)Nmu1cM_#D!QG*{ujW82Q&)WS4VXG4$@IGWzB4f~t6nr$3vVeZrp3&*nXn@8daTxU5?$&+ zgh$|CGp`TRhb3%cE=!rox8~5sc+bXobr!!GgQd5_4C2i8M|}HXpNqYh9udFq z`9*KJ+i-sSG7Su1GyP!li(*p?9$1S6AB9AFhfIM~BL4I7o?r>_(^>Cpw?sXqu z2`n$q^6rCfh21p|O;yClTDx{zS8F3Gw1(OZvlf$b>c4jRo?0K{HX&Ix28_FC+USm)L9?Y zr)rJp5&o42HAAR7^En9idv-xUDLr8HXh7+e>Y=^x|M1V!CEoL~zZdtS4 zX|CKT&aKRVm*1kYb5f-Ez+)Fa8*6z#fDjveD&~e1WzSWhQS3z%J8j;E+cv@Io)Twb zccE-hIFHECl>Lo?qP_I=F|4r#F40#12a9A8C*R^pO~jl$BH;~??JoHJgez2b)k5qx zW}P(Eo>8LLBr+JtLwl2RN3yI5_42^z^rRZxr?k7aa*YM}<9bnIIPUn6Ech4p5~uCO z3h%x8{f(K3anALPJUq^ttInf4sX8{4qph(TAO~x^%AU*l8OR3qkmX-`ebM($LB|zz z5_5;{!q=U?CTH%*Mn;JQGq8{~KKWB}yk(9)eGQ|ovW#>o#`}!+uf>4pXy0p)<2kth zFdVs+RI(-Ib{j0uO|rMKoRYAoI6jw|G{UYf>3e2<&L?+^^Bv-h!LlTIuNZ%U?X1_& zLo)t{+;4;PunVLNw1%gMIK5uxh-b(fqry8cTC6xxWRSKTm01LB-aK^b{_)xypge}@lSj_peE1R{#l$BO7QJWeDaJKcN2^2%wjfUvhUJc zb27`#-{Z9E{k-ZM@;C)ozURx!{d8wR<=|L(w($}S-z2_VvM*xnnfR(`F&FE4SHI&- z?h3fUVa#EG%qI3^C=LHJv%Z`xw}=Q^Nz@$!q4$Y|pYq=Aq7SGvyrOL@*xy#QiFb_SIlCa`4L&&E+_(kwH^A6kUu%Qgnmcq0U)f0Wt7Rw0Rrl^v zBN?Vv^ow&VuJ}EZ|KF*#pO_y%mbDEL-A0KyFRN-!F?02#u@*Zj==~ZDbc<)JA<`i% zrfAAbYAL<2rjB|ZC*Q@)gUDlJ2dPZzj3>lcXQJaCtszbq(v5wvrei1l_K0jG%gsC^H>OpU zM>N)-j=Zc7tZhTD!+G5)(!3$1s>)IgxptgG`gD??cZEaq^*he=EenD2iZOw@;p=x` ziuXh9f_xy(mAoQWUsBc003$B&gD>F!wt;}EUf*_@Qw% z6be5t2Z_B)2gBHYMn*cbt2pH)tC$n{@f7*M(|o$2-M*^As^aeTpu5G0QJe_B$dy;h zL4vnjgbKeww=ZzgrD~pUiUyPLhz+V5zu`lfwJ0k@$!~nIAS=!3`Cnqn5omZ5P1b@) z)!jc6IjxnG=Cw!3Dzo+GCo*Doqgm1!a=(YJ8}QaLeBxpHt-!l;(A~G#(p)Iin$;E% zvv1PM>oCZhS?X>0;Y)JRg(B9wa60x6UCnZ1x9mT){ySJahb_lhejj_~OST&)(*G^y z9`~80^f8tdyaxAYdQ8)jm>V@vyF2Okb28mBkpDKJqFn5@v6E(1pwPvk*ZSy;J zp4yYjD^$}eL4Tkg9VYX8Wi z?Q^Zg(|P#`Eh=n0sff=cSl%ZrD^`J=fh|SkPi^vdzd^Zi@%;H-^d#B!t9a|`Z2Mr3%l;9 z>KMB-zbq#k3k#--`F%;cHK|sIp5@_kB{o^vJs&2ivMe++9&}D-l@{V8u;t6-ei;^J zqL(;bIwu6W&v*0VWj|p^UwJ2XVLZzE_K?aZz5a*>kCNqiTKa`vPrBPF`uG$h{e(Ub z)5l+C0sLW1;Iuk zyxr#>@!H)!lU-E)$6Zr==d5;q!qz^50r85(p*O9-N|QuO>_|Fo5}a)^2oD% z;{n?320wdhQ6T%{GV(lh^eq`|=d)AzLTha4QF}=~Y7DWV^-n$3B<7hhG}F6_-0cAW zJM911ed;XV&!MH6TsKZbkJBapQ+>M)O2?>5oDmu|kso;AIX-d$lAeMj7e%-9dVGeT zt<|fEd?VKVE%j_HY#j+z-s4T%_{FE#&jDDwN%pWB`W!H7xl(rhnlaC)aSTG^S}MRnKpB>scdro9lq5c zmmJ}Ki`;hsq*&$I5q|i!SNB4s*p=?A`+Pw=OMGIK=sivpUhb2d-0%O-fu6~JCc5q@ zC@@0qIYg_*`G2H1FkYJ$!G&0FxzHWs{L@pS{|N|pSgZEwqHe+?y zBYg7@s8!E?{O66_UP|P(57sj{#j7xDoNG+c&zhv4NyNI@2=6b6j}mVr_9oi;^cd&H zElT7vAFPF%!DOQ)!9{lP)x)?{dOlY$IYPKw8&u%g=ZgzLthRbJdKzE_QW(ktLmH+vgJZiAx={_5f?YmrYN^){n_y zzL&Sm#7}Bs44GKvmoyaTP7a~BQFJ{MmhUtAn-gEGi_9CyQG@&k6l6XBxAroJbj1Eb_2{grS|Xu366I*(gk~F-|0l7yPas1+v!Ld zQm&ElO44{&`zMG$Rj`j3*A9-h%g>J@{eQe5?5Uz?;e=vmB7bBr`X9`R+-D~1=G4)c z_CztJonEz~o$iojAVxS}tT0E#+?b!$PtN#E8reo!GOwcMexH$-nk4WzZB?X!()i$= z`jpq2wOHkPklkDhw|M|*>s#9bIKhqvib{{qY`-ge{zrJ;xY~obQSa+0BB+P|d-iYhO>Vmqo(HIYXmc9qe$NGuVaiUj; zB;s$S-Jj@TA)UX#9tMdtoAiIZXR}z%WEQiMeSIOye}oy&V!I1`|09*TCG33|xy8BA zLvj9B*?Bysx#n7r!#?|)y23s__=$J^#eEB>%#nv3kZ*nN{+nE3yr}asznS8(&UMzS zCA`mK7x3Dp_7Ym<8nLg>V(XLk**)`+wUoX$u!(r_d)byZU-nLI3afxoYy$#$?)q28a4wA2x25zTD(H8r%q- zmiir|0K0hH7CQS>2Czva7{`;xkkLExhIdG1D!drUGrG8cExe_c_g>^T{Z(U{$aji) zT-JwE`f!EhW53=jJoO0QIi~NKG23AHACuxo;Z)Z|#!ADy9y^Jqp)0X1;mX{1lXmc6N>JQfm-jKs-)*FmkZ1#AWp39npdz~F5uQwO%PWDwgEU$fek~wpGvR(|$z98+>>~(`zWA~=#RJrQQ z8_QyVHQ3gAzF!jZ_2<=F`Pm}TU^L647jL_R5{I(-K^tiYM zs7M~I^gVV~I>JIeblt6b`Za64ASZuV4mOHUv=DJlxo&&%$Y3nzRAP-ai_^_QndI?~ zv7SE@U0nBD*c~2!&7(Ry>cw9NK;YgmyB2Kxp9mD^9ag~6%BeNn!xl`vB4Z{sBJ?xZqE{`>;#e9HaX!mdI5@I4%8 zn}{=uv<9==8QA0!KPw>JT#uQ_Z2oKgyj9$cGr|(M`%k`=Mm}=c??YsGmJH)0<%?c9 zM;?E9HTH@8&iA60z0K=id*_T##%^M}_2Yo-Dn<#bvggM|gco7ivmP;j^EH?<2OHT2 zaZdBJh$Vk|+>jFcU=0~fkttbz$dbqt#Io@wy_XW#eNt4c)?;E z`x8-jJM7=ZF1FFcI{Mrx(i~=YD}Bz{-FBadZ1O*^U8l192RUpI<0n9?&aA5u>BgAw zeYog-B7QBAq8Xd(z^41t%P8O4X4mxZv7BzI1eX$Ht%-ATg8FVB-f~IhrWw1Rq-D$W zV4JE_^k=GK3&F~l^X1}KK4+WuV?qD&UYT?O`W|r-)An-cwV{A1M<{b@TWd( zi8b?$#KPgpT5MPHe36#A;Q)QfJZifW#FPQJVr`#!P*mvP)!tCF3-sxW54U%XCa@@W zZ*EQ2HA%Pv3D@KwkHO|T@{apq`mLheFRbEgGTg%AX7Jw;Z24_+S_4C4cY;&AAa(`+`4O#ef9c~nk^@YwA#h`+smQonYH%B#JzkNqFv4~NKtG<~M7>pbXg z9U)q*emv+WW-R{AKBJy<9n6ih$_r?JD|XdQAL2yaReW%dczTvk?q^4HJ^Jy|89ui| z1^cM@@F7mT20wpa#O#5^w;{P%FyREt{+d1S*6)>KN6dO$j$a*y(MR$6INf$I9yGvb zUS`A3VI$pC4!dF}&0xd5{Ax+8xad4vhyy#IF@5sjspA~CIsIK(#yD7hZQJd$prWIt_mETn(snQrs z4tKw5OyMRTc$-#a^PSx0n`BU7Kd2Qe;MQR_9dn60;wPJBT;H3Uc#yOvh`jf(myh9H zCw83&x6ZA_&DrxL__d4A{_KpV46LuVs6BQpU-B2C%*^tTFaRs?6f= zfm*Q>Q)I*0Rmt;cQ;d9k0UJM;YaV1xm(+`LK%_Xg>nv&i>~R?uW_7K?Ub|O+Yq?S_ z*K8=esmpd6u>IJLF4nFils-x%a`lYOqIe51NnSE28kKJ%p4 zV#k$MBo}8HG-ORrYIz+$_j*=EJa0qiRd9uy$+UpHx&~?9saIKiEz%5=@7oOsCn`mV*ezb<4?>2vAi#&81KN`bBCX4zrJ>qQ9 zvHqIlldDAe%_7ZuBM(d5X}NsmTd$qdp6^Aq*r_iqi@HjK-xvd1r!JyWg6j@pb(8h% zeSIGyS8E9K>agHA!LN;82j<5~L(^FID)tngJ4S97yt0oJm(s#y8QgN-IF7XyBcBh& z!yTexoQg3UF6K|!m!^%~Cwivjv{&ZOa*`>e`@FajyXoA>vg4$y1iqY!<(DMiI$H4p zU5&<%=g1XT!qX4kc|FwK$alsheKYpII*V^al{hMl@9Y0;7Pnjfk0mwnHd(KriDe#( zNPUOc@h2NR=da_W9P@|!gp6bLQSbyH%alZK&xHJ?tyy>+W5bI4cdxAao#AH76 ztuI81eO^6E&hvfd6_z;9yYtAqulHJ#Y!{#FCRb~Qk3PwAoB69U&%7VP#0u=FZ!^C#=%xj4giGutt zhv-rgI<@1CU1)#2n)VjB_>S*Sr|l24d$Cp3vtaEhW5ZSSuRoawzQ?NbsNXlE@p`m< zuQ9-$PW$*WO`Vhu&!7$(uTM9h8-JS>v!xlm9#F2-7%h;hF0?On*8n`Gq0e5wWLQI?R~+5c-{!)9^zD5n3dEPb=Ky^Svpg3&!lKW5~|NZ)*n>_u7C z9kh`LZ^$nb%`IcP9iwfa8r$3)ww(Ujm?-U$$7-Qs^1p^2kE)eD0JF--$7}k#qb#ql z*>cT&tDbzlq1ti{TCVS|J#gXq&}$bT+~@HXW_Q%@Q+l2Ow#LY3?9FjioX)0)B~`I2 zkxm)fzK)&#pyCkw6@I5~o|Y}vqm%A@u?Z=*##~0Ru_5Ba9CNT!QZCtn?=OsPq1P+8 z-aqQe$Jx<$`YUsH_Z4h@H|bts^%Y$0d44!rWLPY&I13_Wne`OA;n==3oz$W#s(IzL zS5tc0JI$hh@&9@A8Lp|!+|0&rO_^_<*etPZuqs$zR~d^>E)jiJL$cBSYRiB7=u7NS zT;E+|2H5lZTv(rP(BJgz{wgV?c*VYHJh~9A$4b>tSyNQs-^G$AYxNA?6IzR1MiuY4>Wukmy8|6o$p27+37P*Ykr6>%8Sn>Y4bMvE#Mp3#O8kzZN&73V$fsW>qg@v zJo885!UO3t?^SljLALY(VQyRZ7I2Oi$v6$Xf5osBXz zQUAP$6%}^>@+{|Ge6T3XegJ>3sFjatb#EBm-W4Cy?xwWSK#OYg&)Qypf@QwswZRz5 zaQt;E|BBT}+oAL(SUr{I2Emb-ogSwPU3QI3qard5LZ+kY4I;6!f)@Pv6tcXBpQF+BleWI6>`N%BrCOIG--iI+(rCWApEn%Q&!70o8Q+SL){O31fXCl1PKWoG!w(BX-aByQJ8-EK2yqUI9XFHU zv|J)0Y-Sb~`;ZksaXd!2$g?*^<-uhC9?MuM z7Ef`#Dekwx_4bqO2?(_xDt)9aKf3?FG?|76q`Z;&YY2N{h)HUU9BJ-f zd0d2hKj9F^$@~ggT_OM2D>cTW+N%dlBBj_Rs{kH-4|(5Y?rNOf*H+(ZlS^5@i;>l1 z?!DBv)9~ctFzI=|z7d1EE@i)3`vCdKNftAKv^KNAgt6`>P+}}*B*zm|Gt2r{>17|R zt~n2C!B6b03bFcX+Z??=tP}t*Fsf zzTMwrBw2P51=@=5Q3IK&?ZahraprW)sh@;-O~sKXLF~6_c@&w)r#txcW0*p5SAE2% z2e{fW+I`34LtO4-zhh>_01=?C-oAnjwiWqfd2%Bn-`Wd|FT%v;Cb;SH?@UH_Li*sJOiV$7szcYUx#2Sb5=SiZ?BDS#{O04G1 zvAh31-nb5?{3_eNh0gNI^owhMb$xH8zb$d!7=tOI=cT-Ii$|Ow6>G@y(sXF;X7N26 zZRPdp!sJjmS@Vz8p#@oTI=_EXGuvwne1;huvyC0Z`Hd%J!GFtYvdUC4v!{RUdy`Jj zFB&h8)17a2#e3O7S&TC?-u5L1e~|s(s2!R7T$dboIzeLlwf!h8h!fNP_RTm6^&}72 zriQeHFRy`5aq6xyJ$G&|m+HalVw|J~jvJ>DPWO9;mUm}iecfxSd&b!)^E}(cg1*B4 zf95e)*uidjz?-t6=`zj(GJ!oTW2szcqR8^1N>mHaE6Haovz*H8vNAoEV7JxCv?VDv zXEjf-#n_F#hn&B^zs9)#vwm(Dbz&{k4Wx2HUG`)A{e*gA4)TALA9m6E5&AvcCq|LL z6cU~dDF%`KEqrVt6zI%@hx6m@SXN2botVtSj@Z|Dq4B`jRjUwf9p;5|S>rl5z7xvF z4n8p-=5F`7j~%zb;bVOJeR=wJENKx=HcYQx=Uu~Ttd~axy@_>&KSAplL;8$uf5OsZ zt$gfQ9JSWiG3KOb@HcG)GNja^U5@$0*3y(UX|#JjP7 zR}qo3pon>oXa7s0?ENtOI(JSF87sR^tP+lWwM($nI3=kyX*|km%0cWHldQz1>yYae z`O;dr{h<~g#vJx~Smh&{#O#IGEhNrEI}4|>`s~f>TN&AH20h3HqjJ#2HC#T{Dc;25 z>_24I>S}g<+BjIuV~_ndvS?*t`iOmqV|V#~c-IB8jTub8%23XU8lmIZ8@eK$HSw&i zp7$Y@sEEyFA&w%3b$pkCV2xi(i}FakdsuS8o_e2aWakjK~~2CJ(}q9#!SNPo8oQ4p$EP zbm4>VL!b{?#@FmR@`X6#xG2UDvqQ77h@w2dR8ocu-3NP5T}ha#$fVc!>!%*2=)_pFh+Y%$xd$)%L}KhH4eT`9ciw3 z)0_ntNYjpm*28kzh?Nboy1H2Qqbfd6!_pU_=)&YkbIcZuDnrbk$V`gYY5(=m|F&ct zyD@2}7qFgFEbJ$ri#=iD1kAIde?Hl23GbBkjacPcSRJIGd&elwmn?82b~BIFy~|5J z6V+p6_E-1&!&Q!u**yzg!NAVy67Nb;&1*ltEMtMeI&zlIO~rHwh+dW?)#hn)8qDJ`YFjd5|Unt@|s}7mp zjyGwnb-Ipq$7>nEE)L-x!NERyOU2nDSNBy)wb+;u*V?y9Z`J%f9MR8OL*t1*-$6V zhWj0hjJnZ{>@fCK>IRL+>G|8PFpob@V?nXkYs`lq$U=vzFO18SMyGFmUpVyeIs3j?H*?H`}oeg?lKe??Izo)0;}4K<$tq{s4+E%H#K1Lzv@B# zwefDF)A{9JHOXcOkJ<-qv%o2{``m9h+v_g6W%IL`XZDt_wdUn*FtA2eTilLCWsuvJ z)zfF8VGs5=Nai>W>W$LF5xgnpM#pYwEBQ?PKCVCi;jY*COU#b{T^!giPVA<^V{r0& z^HG2D+CO$zNsvcA*d6;5HsvFaYgdfzl@tdGv9H*nGLtA)37xwWikSgz$=SZhGWhLwA#Q6O!JI@2lki5WX^?w|GKjPL*H`41kSssoMVZC$+-z>y;a(l$yboXQ0nR#BE9-Nk!U4p&WSW-s*d4x5^s;`@T zrW|Z}PU{C_7tiTOc5!+SJx%qArBLv^@86E;+-ZE_M*Bj4!PeHmso0gTsHoD|*lbrE zW1977c5F>qA$n~{j&W_3s}4$zW5=lEA-1sxn}{7))?ipMe|U=;?;@IB>i^~bU+M9Q zd!KOapXu=;ZRV6iMV;(=@jI=Ue4{ad4A9^fc$*ey`_X3)$hVLC{Rf{qrrl}GaJtNL z_Nc0DQ};NjMtB4QZu9$d{AL5cp20##^UDeD5vSU&g?9&_!X8-oE!+H6)|l2RtV~wC zWOnaApu56k__$a4eBMPNw z6_;RNoZfSu40DU7cd&@a!Q*_V>*@S7o)x=u#yJl+xOZBZlnUA61gWgXN$-Jncd96r zGAFPSnN}sYhGIq|>pknH>4E3G;SSSiZl#v}Ec-kohjp?%Ja5N0`f61>k-Zemixb%| z``mTVxrqCf=Yz3(#lz6PA{(oUQ&i_Ik76uw4n|qbBq#QCKzoM!X+xx>qJ^EfUN zv+{DV(%5Su2TA`U(r$u?{b>Gq?D_xq#Om*rb}9%pSVsf(pmw6`bGY#kQF9>NdyTEG z@O!_Ou3`yeNPLoLFoh=8YQ;BfBzDvemRpq1mKNt8a{o^5{2Kq5?`H#kw#P`}K_hS9 z;(1@Iv~A`oJB?HxlX3rNrSTtr{#CKRIpvIXg!|ysC-!Rjz~e_hf0+OABOdlSj=2{O z#>~k${p&_cG+`jU#rJmG|-!`z!Rv+s3om$?(B?L77nn_!INu|Iy;m z{ih^+N{mmX&tL4mwMo7IJ#(oyV|IIu_% z{)c4Z+}*~;KI)`QHKNtisBlyDjC9!TkJ#`;t>`K?^~8ZXvXk*N-A69+iYPUl?;nSs z$Mx?E2o&e&?&VnrMBE)DcnnYZoP;jwM_Nej>=yFPPSTm!=2v`Y1*C|%p3U5MAqv9gCzz-C4putObz^Vfx$@d+=3Ksp zv%bL(7xBNvS~iD=j>1{G`(7vGbnP&^&BlvzrMZ*Mm4|IjXuX37IgI^Hf~<3Jl2O{; z#{W;d<|rIwz1Ke%WiPYsY%-^qO;e6uI$`M(dD{e!o}R@iR%gjzCbSp?8M>Mc(acPT z=Vj0D;2VFylGs!%2=A~>wJOdjJ4UzDWwCO>tnp_8CE@7 zt!)ITPgX3LFTM|FThBw5l3H+r#=`oJ(o(En8wu}+dTpK-d@L5n z?AX6p=wCFo9j{ypDdP-<*qLM)n{DX|aURS{uP^4O3%$49m0}*&S8U@5%h3#%R*a|XeTH* zkjGDBwbSI4t9bGEd}0?=Ud#8^%Y6@uR=dT>_xWiLGAJf;6oR3-WfV8U{OimdE@5~6 z2drHxW2SVmWZfX5TFg3(6J-C;i!5T=71_%_c<^Bne!tgZe(h;}JFfMSV}-}0bJapD z|5hG+Gk?6*<9_2U%|zc?`tq>8T~7{YeCIMmDgzJe>sJeH>xkDqPHRzLFCt$l>N|gG zL7Z6@RluXH;WOT{maTq*Ma&aTzf1ilcx1{V*fRm{#~#Ho>u(lIe-*NHVO{Uhal-uU zsKpKwBPK%rmyN+Zzz(iK-a|C{l}|0_okO5f7vqsHh)XZ>hB%dWJJ#}@NVHdvwvo$m zmXQUvUXO3)gc-3rS#Li*=-@@j(_8!<$i~Ns&8^%e_J1vi9kha$ulwCg-|F&;s;*JX z@4Q&-%_4BrfntBE?07(*ME(MLe8sjl%AU4ChF5rKdm}=FjHte4{?-)e zG#H95_4-m7+57s?!z1RO_D~xcZtsph=4L%4cdxJBUtNw{L-ro~?^c6ux4@Gu)&i!r zXU)aL%0!OTt%+N#B`)ra>$~l7SlhlfxqPNH#3&|bsl;2m`0k4&)>VerQTrxiR)6Q3Yub5vEXN_NCDXB0tqllGWedi>E|Az;} zSzI@g=KsXuYHHS%lbpIW&NB>4ij%0_WZvxrSj#=~MxAKzIZ!VTar zlVQjZ=-&lSyaqX6$D!MJbS2SP_a8Ip;@tLK@a3R(_VHR)pFEprLK970=SSSNCtu&A zN_C?d2Y;#jjv&o6a^uPJw+?W>4=jHf1M3IXr@3N`DaR`M>g;b2=CS~PS|nz^<*_I^ z=ju(>sF)qx5yxx>Gw#*?+u%kPwemRIG9!zzq;!0 zFL=wEWL}Yt-xni;k{)?+m;ZUah&o3JnvPYvrSX`uK2w3j<6O^b?i8mIKSYb|Jz|DY zOOmZ3z8A-Hi}AApILz(zem~@odAnKlJgs`#Wwo7~SVle?e2^d3^C(6Wr95lFCfbnE zgK#HyA8hJbb{hXlUF0Nt`v)^Sj`sxbjXk#OU`u^uvs*==UB+vsyFv?mG%d~+bI5*y z50~KNFHmhAYkx{iu8nIvMUUMeR_y#y&^_vF&p_TEC*AjV=V!Gh)~aNL=&^cnF3fsa zY<`M{D)FA$P;3fso(zNfv5VOrGw6GO*SbNao{(WC+xrbt{EpXsPI_nbArllW=ut{G zP>uc`ao^fx@&vqU%?Dm2zutImj4r-Ga#Jy=Riw9^E%YIWT4F;J->NPH$>norRNpSC zNydDu()=M#Z+bAvyJGLWqw<{n?s|aUVt?6~n^OU%HG+CoSba|4k2BOx=;JBz@wa4L zTmx&DC)Xp)RIym9=W|7u_Z8}Or`2aN1C7WnAq(+&a_$&fi{rTa#lH$-Ay$vxLU;f63SeM6J*!o{BSzI z{$V=WT-;AKHlIhI?qp5(`CW=NT}v|fI(q+<*IS8Gz4W!KJoI_*#@=Q9e0w;?6S3h1 zS1HeH;+(0Y+H{a##IBh!H!oFnA$I94!oqqaZ8$Tlv{$b8nzQ-XMduDb+w`Fh#+)BY zSJwBa$v?_w=dtMZG}x7v(`x5-y?>j0YO%pPJ%3DuYz2)6vA&Hs+rKzlahBgnEq#g> zPNetVbp8~JeniE@PMBg%M;d!Ti%XKjJy5rpUgQwB(!lK4pLaix-O1y>!pEx z4v&b+cqQm@KaN!a8rNVuEivg=l9i7kaPbXo9qQiGNo6&wT&;h7_{4KQ8)r4X$}`)E znmu^+RPCCncXQ=p)1lgUDE~T)ny2Mam0zOG1O5M!PfqsQ1b3e2>bqd>XTC91B(CZ1 zWoaZ%x>lh`dd3~}(wKF>MB}ld=MlYrl*N|NhTQD_A-!(mTh%;&id{UxI!d`h>`fi} zOkBtAW2SvB--$g(9^exX^NpBoS&ALp>l67{${!-(RTh`U9upU7{(C>yLAcnvGZ)(l zBu%07I0+%@nvuzrcg39EPv8I-eewqP$U|#cNk2~H+`w<<@%|YyrZ|`62J&u$*ACX= zhWZ#|*xz_>7=~Y+S6ocww6EO1)+t?wIdR8|38rz%e*(}l+PR`|3wto<#H(@<% z{EpL*W5>axu988^%hPXJx~$ChYLk8gw%(eL$9T|O zua99jE!jZ@R@jS8#9WfDtSV+R#vZzHTH^iutO{$1IbOM0b_O^T(KlAN?D2ayZtxSS zrQ@+zSVo+q6SFGchjm@A!h8kL&RfpWh43zG4?UA>@1Pp)UO&TDLT^80HEZQGd*Sy{eT_<45yclutdgP|9(mZa1WyFgJ6rak$fVv%Y4R?+a%9|EP+5QI442oZ1r@ zNz9vC!q-Rh?UsL**-_hRTgjHUP0^YJ26%x{T3LEmBVqj=CzIrr;g&NRK6F0*b6 zm5Z_RLfF|ItSP6y#)#2ypPs_9UgNbRaI*!X-bS*FT?F^AnS<=>Q#|nN9e=1Fc(pW(zKiYTkfWRwYrhqp{$g8yvGz3o$I^Yk-(3BF0RP@ni6WUzGRi0; zLI{yU$R;BzB_p#zRz{(ug(4$mCOef-l958m$Y>}#A(`QR|IhdR{e2(Tz4voJD$_r>MWToE%L>kElf)>yaMfecnwn9;A^E7-_qimsAxJ#U9i#%P*hy zp5RBdL-W1rR7_4zHD>Zoa*xrIdr~VEo3=!KpkrdSWjulBapYkV zSYK|VC49Tj=t~KIP35O&@vaWCp9vmbtPPB{1~;+;H;|{>^}GbB2z0!NBioG)Y$qL& z+rNP?8Y{?h;z36AzS7yTn(RM!iJH>q{U15<*stm{y7Uda?kjH1rU2jnm2W-X<+v$Z7l71#`6e-=ru(#EOU`mRq=uW1jj zBxar5MDAk!-OoI=f7pYYaQrqHT$uJ&lrgIbw>q%ZgIU&*bZP{dirT!fZ{vNmw28Ge zqiF6#bEaRU)kDk|S-^@fGw0_+R{TSe_h>e_jw@mh*4Sq__M#rZx(}w=&+yCJr97|0 zvS#0-?o^&|)Hr#HJ}uLx*eU9M*f@|x&w}&Q_zA5c!+L!viv~A|bUKoNm>;kozjwnf z*)KHw(%iUVY)I+!kF5iEJ9&(JowF(+w-M}`aPK)@=1P|OW<6;NPdaE(5C1kyWQv*e zm$AZmXhs3&6@!zNy+7mW^T_`cR;x2S?F47W;@c9x*i8;H?=i1pKGfa@#jmv++);BZ zz7Rit1F1Lg@z%<-#GbF4ocopbtdyTxELM*w{5@B{CO6dxwm0z0%cSIevh*=ITS{K0 zu@xi9(376g!7qJaSACIgQSwre7ugWvcXZ9G*3S$h3y-5&T|6s^CNVoYD$s4vv)J7} z>W}UgrI*p8UTkRWu3VYS#6I!6`6RKo>aVnM9r})wA8DhOVlnG1bDPg_FT@&8`u2-~ za-hLIa5jA8s5yFsUM=BG41zRu%|N-*TCH!ab^pL<@Y`PRB)3@|{;P4{{mIo<#BWXh zX6<-pvuLZpzPj=+Z6M*B1ro&^#y{yxNZCB+%wuPua2+{Ek_k_NG>j^R!s6`MUdm z$P@V9`8(;<(UfQT6YuH(l-yw~=MF<2U=aT*}`HAFrsrmQVCjobHs7 zi7N)hGLZR;V#hq<%)*enA?Y8=D#YFhtx=%?ookFw?fED%-?Jj!sOJ?s&z1CBKCQ~k z%H|O56~w_jI9eRt?$_Siv_BI*r+f16z=le>TF6$I!QyCr9P}0_a%8lXGfm1}%%)Mc2^TEYPoj2sd`JC}g#popWG9 z%r1<2tUJ)=dpa1qUVltuV)Q&JhxH}t&HPfEj5p&u*Y`_%+0Op7R^5M`Y{GWb_FGjR zMl}|>B8#1aUB1D2QJbNSyYzPF7#Zn^mv^!=O&x!oJ^Gy7r=j2@EKDD?X^$o`Zzong zoa85jmeqs(53pdL;?;xBh&F)gm>lGQ%Rj^~IUUs1A1?lS@^nHvLUgU|y?j~2ERssC1iDR)=r473mv2r_J=36)x z^W3NL1$VML`+1kYknwoNL9fGj`xA+N7Xp9kuTGc4+oImgYMl9ub}WG{<6!bIe}fzy z1$W+sPO)F+RzBBe7#XM;JNLy-fU)ZP0-Q^t`c=j;_BwL|9&gk8@8IAjGjO)@F26N< za0U)e#Ix6NYBa8n=CeMtj=0c4^lovqZ>oyHYA~IO4?!s{DNP8_xg$ie(E*T`4h=Z ztd)y>yK|Zi6l*oZyLf=S#M*#2XofLYzI?1$eUDa$RgY>IgUHqe7PhcDOV=g-wu{jz zHM$;3bWcoB2W?tnaiUqGqxwpF;bLF9U7A%pFQ!XJo17xQ{B$Pf&TOL9n?zTqA?pK) z@2rE%ndo9~*!GDwi4N}9*WPo_;dj?WQJ=3*j1a|jPke2ST-+e6OY;`&eZ_(NXY3jO?1TQ|A;89gXxOBZWlg*ULj+BSJr+ zEo)NaZn00vX7+j&99jsu7LuF~NbV%}ABTd=Qt{DNGPZ|~Z+FIAcOHeF<2-SK*9x+? zmvpRlk5BY&Itq0|pMK=*r1S0)$K;ULNb}r%^k@OynB$rs$nJ;m=s8atjV6;_AM=<$ z7rVq*_H{g}#Uk%BB7i@6cH`OKys-UCay(G`I_kqR-h1rpwgCR`aNaRiGQoE|3r)7b zfbsCHHvcl}QpfIC39|Srs_sC)7=zoVFX2U8!D_@RxEpwLkyEP;pTb{w4F2~a!QDK$ znOE!#*AG(mgF9ipa=BkRzGN0XUned*#N%BmYqQRK%&LfrFEjOatRD6Bxvgi`f)n?! zjrCBow|+nESP$(8U-4&g$w3s2s?&4*KHGVt-F+15O>_KxIJ3-CHq)e?G%0rUIZtXb zXmwV9|BwlzIjL30i|OpI5!2uR;S<}&ukt}B+Q zz(&TtWU-5VeI7}iHyCyL8KrKo^|e^$SX~io5@Kz_VQoIDzZt|rS=ovQ@a=j0>x9~O zLhh(f9qW{SBz>_XQS7I%jtr?Bf!Z+_yc7G~mL-WQLGOFQWAc0|?j-Z2e~>(pyp*i$ zs>LbY$(i!jzaUMMXlPefx0Lw!9@)qHtXC=rXKUlz3#hfuXmi3HAB0v-`F4-9O)s;A z)A@trSf&Bm*-p>OYWuycQ5AHrXb#*BqN0E3|898uE01d%y@^^(>+tkFJb4L*5BK{> zx;P%E*ZK8lM<%fuCDdxa!T4zxI=ta-WO4Fnh#LERZlbAe+5S7kpQn<`lD{Mu ziU^J-lgVnbwNvPStRab9LyWh*LjxwVzHjj%$7=7JbY>74zMZ5Wp`qurH5YoHNX_2O zX%1Ot^U9(McOIOHS&BJm$yK7C%Vq2fL6HJp>eRb#i*rAREI*LZqpbelWbAjyvqP33 zRwB-3J?Hy29ZG$N21nV@i=x;(^eQTcS0G_gXE)}16~*~do?4veme12NdB2-pJwYPd zXlZRvs0!VSk+b7g*RL_}X*&7ez)GjNHs<;rBJ)|CTb>LRBcp|JB(LxJ{F;k&pTqs| z(83;+^sI5RqAPhp8~NsI_|}cJ<|uvr34(nOL;rx>ze1aFWTT{+x3M1O!PE?(m|q)v z>b2z;O*K30OLZxZre#a)=d*8O)uIw&H$LR8sS&I1Y3)e&ZRhE&(4imnd5v9NsV#r8 zJ161dDU{3V>{|NLknS|pgL?ebsOJ*nAg__?p|YN@khhh_J9hEU{}i?U=;&@X`z(ws zk{FfNBr(LisgY^r&0#poR?inxyvfUo87yz{kX|KEWBEZ7QTuJ2cnbAfc~*G;*YJIh znJFB)G=Tp&R4h=7=4Pk)rO>7ZJctZmVN#Quj$eg_*U5Yq@P0Za2jMNn7{x|^TX24< z&*Oc1S1%X9`=#vRFuK)&?Dyicyu}ZS-DqmbwKOoVprv*GwT(BF_qo0~1?|i~>OmWO z@X`9h%RX%JI2t?0)$?fUYPqZxc(TzQFFGR+Py9G}`;ATck*@v1e~O&)UiM}?YX9lz z85Za_w&s8JaaU_yRLk5?6PLNqGQaMmjVIZp{j}*fx|-SSx|las61}1}!t-Rd1KlV@ z8#9u++l^ROB9&$N#E;OrwsdVg8t%rwQ)s;g4ad^ru_C{(ShjV3Yf2_#{&mcIjT(fp zPWOx~bp1pQ`|V~T`k&5 zUXQ4aQj5=Yv)4|U@z@<4A9_T)C-O^mupaJf>wDPhOx0b;AFJ>nvZnGr<>Kj z$P5*;$v?%+#i)%R*{mx`+hwxm8==DjS5HeJeB?f-p-QYNTIcS6XhBrNKZ~1ZwC{R% zCdYVPC&m~8!r%&r+C%E~l@1OE@mZ$uWQ*{2cp8bJ3Yf))3ESSaG9HAqzsv@eQHD*t{ z(eN(XRmZm*>Esox?-59>eykRl+YS#uNZ;Z7mWdr{gA)I#1@ecvl|yAN$~&4zl$=ZC z^rYGNYwSONF0GAu_3aaf>~s1l-+h=_tc}RUZKCU_JM;y;nn5356n%`4`JT>~TTV|_ zYHid3$iQZt_srO1DIc3&m^|es=>>hh%RO4riP%+fG>mwQbd7YpKeXR~j^00jD@nja`iB;i7bNp({XKY5VJF<&C-FLj6zE8H_Az@SW zJLW3Rf-CRAYZ ze+lVlkc-HBJ?+=0o&UeRKc8d?TYB=t^rRuX@*J;knAm>;$%-mV@4Np3Pl*Z?Uy_#C zXY&+!&nkk?E5DVAG@d3eX{7BJd|3&%V!!P8_YVz@Dr`|_?0FJBgygg)-=*2rop7ux ze%2yo@B17h!!2>@Ih1{hU3h`Ke9U&7flBvSdr^suY===bNZn7Q>{<91;~trfN@X-d z>=tqA15o*CJzR)_XSMMLF?<`y*Md-f<^)Jx7C;CUUq%G1U>+^eoDD!BGq*TxFtYxL-Fs$&21_#bvE_T!9-Y+;G3 zvhEM)?fo>Rsv|M_av$#^uj5&G0vUL%zp%RNY0!5xb0yqbMrT*k>?!bQ3N8JdcE;*~ z8O~mcs$rA&qt{Wh4rAAaLwu7RW*F^|&-%j(ve=L7a;?3b3=;bXmE4zN);odPr=T;hjEtEUUYl;=TIX&xke--dM_H4^e`)>7@&-a{; zXLD8T0`LpT3SIl2ZTS&RKZR=(XvGYuJO_Q|kjKy1ff(7D;rRb*gH7Sbj3v*L>Fz6h z(GfBlukxec5ZeqfUiK2LTa32<@!uLlgV>9y39n|o>s!ecT}wZ&rlAj!`4KSfpnQ0J zeSgY%we|M_-||D8*x}(Pe45Hri2abe@dTcLPaS1PTFZ_+%H|KJw^7$LW;jKZG*vG? zRQkZ zI`)^%d|wu6ft+AeM{7mWs*}0<>1EW;uFL-4NlLQ#>1_mzCh(Vp}ixoqGrSy|=HuSThMdME2p4%O>v{S$OO#^G9^$Z(e7RaU+apJYHPzMcgoV+Bl8&m4#| z(`BRwXz?BLSwa2mj`w%|9_X3H{EiHX^=Q-;=RzW*n#*(%!Bn~7n43O{7uFS)HD#YW ziUYndW|Bu#WPM^{rCj6gv~h`l?D3W0J71 zM!|ol+xwy3QW_PR(hvCru_xD0v}~OtyYMs#3$nN_qnJ6Xm^rEkUn_pi3JsI`v6HRY z#@76d6Jej%@+9}MQ%UyzyiZxk$&I|e_~l>E+{*)5FZ!9S6)}_hb4at86wT0C6mHfVKJUU*T@o+rW2x!)lE zPfy6(2j#*OXbVFg@Z?(jrRI>R9@(w#*OGp(25*{p)$xBRFSuNip>)n9w+>>-q zaOW|+teA~Fo7CHbhosFDIsI#0LKgTNRi|>KMz9K#m;2el9{%r7M_ZAW+P<}56}z#a z-D&KT{LW^y^#wjnWN2b1#kJ1d#4dkAuHN7~_Danq_{23)01roL(RerzdoWjKjep0Xfwa7$%W$HJeAG|D2V!bY4MeOmowURl7?O3dv01CyZ+qD9u`F5 zN@&)IPCTG@weaKxc6B5a=m?dXIMU4b$|!nEYE=0Y368wb)#N?aA4Dd2C#{JJkt;+z zf3hb>qvTvZTVbMxr#6q(**o?UV0)pEQI zdAuJ27lU5+xJS%l$Ojwq`77(Hm=E?`%HNIstatGWR%rPVIN8#*8_3orl5+uC9~7m3 z?t6H&H~KrHH^1Uf>?S(`*WQB;v36l6UpQ}KtvvQ5{(J1-o>Lr}o!5~aU2o@+cQmFv zPd&hGX;l+@#Bkfl@wchDFtP4(GK`HqAvTbb*by?u{*Q_<{(=wJSQ*%mPt+1kYmw(B zY38+b8IIHU5tzV+Wy9w5GV;JV?``_Cagc^&-_ut^rY?cwcWcE(UME*oow(M*wL)3uWCq3&Y{^cw! zkJ{Jr;5`Egxr#(xWMyKN+fnvu4;p-hDxbo^^?0>d8@k|Heb%89 z&$a;$L{;NQP`Ecr4}_AFaA3J#zDDacFl;r7f5M}S$p0Nzzo|bX$U&gr1pee(X!J50 z^O8RHbG$G667`{HxNZsDU4x5iY-vl(E{UvUx0G*m0iq^(Lsy~1Mb`BUOPPS;F*htc z!Mb|bBo#CFN9m=wvYSV+9qKF~{ZXsCBnht%uN%{t+9J9q9B)lmqWV}4NZ1B7hQsh@ z;A;o?)0_r0OK~|TT9xMwb)=0$A>eTO)tr9C+K9-jWW0G(n^BDzhxtne z{AcZqxZ`v5r`8O}?u-NSjy74i48kL);XwfrT@f2No9FpGcSOp&56I$J$BtFS^ ztZ$U~UU{9^E8`VX8)Gg*oZH(qBOp-Zaz2AObM^QczqL$dfxdR-P88e213l>1!>(8h zC1+~OJlekm1s96YB1^cO9Io>HFZ~Y7TL>!WLEY@^P9fGI=H4ds|8J4)MR|y`u>DW< zR*t5tqycSXj$u7|8S`rHuJ+WLcv;0+myyo%__Kn~`oCJ(v14Ae_kf<)o zEtOUU9$!q}Bwv>iJvzhFy)q72we&xdyAvHgB1v7uxE0M;%H{p6xosJ(45%p9??uCx zlg~`7#{;b3^K9yPUjG#Fz=!l?IN699LPzjB=F=Y}%?JJcL*ioXd(1=$IsaXx95sR_ z;>vt>VrxqJvm2MpMfQvHzHTFR>$N6we_6G3ZL*aW(W7OHGLx(KX!;Jh*$t>W5l3p% zq5s(MsC*Q=3f84F4Po;u?sEv`V$D=vp5R2-xyGvS{pNrjFqh@1{mM`IwnZd57oNN+ z#(TyHK~MM)`>HiyCu7EWMY3H0$8!2~Exo^%cHQB<61{o^r#kzsCA|y$z1guGG&Pqy z+?MiJJGd&==vUSE`(Q`xQ(1urQYyvkd?^p@HvUa^?X2t-`+D|phseQ9!o?Y+;01JP z;JWJK`p12LoL+^@#X8t4Nzys_rmM+NKJu5}Na4*8EXj|}oYYRx$uj8yTu+7otnX zJr9`uc&ixWDd=;?Q=_Wfvts(U*rr9Y-m`srn+9}1#WLD-zy61{UCKg?^5o~(nrCTa zPa0iQYwqS7RHMDMv~9d!cEY7ybo)o&W4!RQRKyn}@N*%@JEV82&oTPAk0$&;&Uc?drEflI4?h{%U;PFD}Y)#;8l3IF^0Ad%6;km2pqVUX6NB6 z=SG8^Z2xUClLc|D7=N}VkGDQ)sDk(R;%;U7(-7C6bLWBR-c~Qm;!?~g%@22Ty6!)E zd02ZlYvEFs?gu@&gyKmEyM@eu&OhI-7YXQ-CjYmK{08#JdfSzH_!BMKZyfb7Og#$` zu1@)n4cMk~?jP&&(%m`waivdLQeI?DQd)tol#&a+TO?K<&NQO0O?fNT#aFT8MOShZ z^(H%}IA57hSPPdrxMK(RXsmY?>3SjGZ-ZS?{jsBKVitAGXMUe_#(IsYbsqI6#(6>$ znppW?qlBzN?9;s;%I}8>8BiovwG~dq1+fEq)cTGZsWY_d z3(uJ%hcJw{G+3)+?PxuGi~SI8q7|_R(l7Y&vpel(L-&%b*qd`L-Yh}SHzC;!Tw0d0 zRwr=hxL?+}=5rXeM+**+zXZgKaps#yPV7|_BYIiLP#WH6Nqx?MFHzMt>H!uO(cH;K z-iJ~h=y^Yy(~5;Crd8LYS{9!Rk=W}=?_W52Osmew6mDXrw|jDAzIJNcCPz2;{agKy zG5<4;hEIQn^yD)}ahtqLW?8u_Sdpkm6ElvZrr>4TRhkv4LsHB0dM~2FVP|C$h2}&3 zLh$Ca?;CvDKU{|W$BYh+vSPh$j&*rf<;iWe#)wUfdZ$**$-%2 zPbf7*=5ixB-RgZpD$c6mt_hjdPeg>TK&D6e7Z;6a{mBMi&d<1qU)&jHP2+3Cu6J+g z?MfV9tJPa%P<}H8{XKNxYnTt&k|sZDl%yFRwxfqlw7QnI=hn|$Y}^f2u9i@3qc1*u zh2N`5L1TKl)cvnDp0*vj?n`bLecjGyejQ($fBz2(+_sHGs)BAu50=_<9O>*EkB*SMYg)Mc&)aGC1%=95x>Nq){(K=30LC(72fxfuM9YRj6}^M zWv_`#UWY$XaQSqH_+~UG$MAU zE`oX`alQ^6t4W5VwscehjZ9E$G#<`oMPUT3$Zx(AcvX^W(RnQ(w+>`)AY2MC*+A<(zJx7{1Fw-o!?fAM{w)hk17;9i-UEAxVZxK)9bAJ4*+B(5& zBn<9F7uxCJ<9c^Lgt(k-N|LdgAyv%b{RyWM);Z^4rP5&KzxeYP|8D~te#AF>AIHYy z&RnuNpR~v9pbNA;9b)`WTVvkVE_!#CzMnzU*z@BI)cPGxY$dll`AXkIx^<$GpIE(J z&WjmGlOR~^Zu&N4i5UV*>H7}a9##35dP>v<{ES>JVX?ypi>PN2n#8R11^76Qy`Ad& z5)vHq7#FgFYyA?w_y4NiZN~Gc5WJiWPGZr=>em!#)y?tBuB^c)s86cekg{GPfzEu9 z{&Eph$kRZ+LkoF`jwz2}rQg2875j_3Uw4ukBLH)7=^Gx;YR{gF3RC zX2m?0w|tw957V?_jP^&LW2dQ!eB}>V;hxYf*60>AdUPRqxe?vFMaykmwFZ~-uu!#F zs~T+e{d~=8Br8xkH=pE?GnVT|)HJC{`bvsr3h>R!kjrLbpzh@1dC}csIvlIbH|gOq ze^CWHFPoAtQpREo?2Fj}u_wW2 zu8S2fV<7kkwBnnTb(qQ9{K~iWp8f;bh`AJbMYR>lcrnpZtclLdx4ILz@1_fP@(e?3 zma`bKQ+M?8D0wU>-hY&iG$02t2ctHQv}XCAWHp*XhsvlJD;V0qo;u=!+n`Yn+FeYB zs5uWLc6rX0SZ%ChgHKCI*%&DHSjtA-3bCrdqR#x4551PkB8_3ihVqp@6QS&aPm`cZ zZt^)EeL9nsm?3c+PpA(`e4W1&JJI!IV=l0rGa&W=lql?VfyZ8+mc%X(BT3Cx|HmA^ zSVKAzf1hPd+LE!Nq~kD6k6Jz}{r`f`F~@!!nHz>4FQeTQk{&sNSXuE7iuZEQ9<1dv z@`F#o{KmZb&Zri9zpO&P5!%toud$y<3(t+cYx={;Q*bYLVivrO9RoU$!E!8U)W!Rr z{>OOfJD&6gnty@j8T9Uc^m_qTPdB4#wOUa-&~jT^_QV?0S*{v1nupj08> z<#6g|5`J~c2VCpUOWY~yg`b2H>Coa|(jU9$-NaJla@{Si{$Kr?%CxVbR+T1e4`^RA zt!YPVN;wu$Ty}j78+W~D{z7Aq@^NG4#2qLTt7NK>sj}``My9+T-=YePj+sg~_@3aM z{){t6aP|SuUWBKISeUga+trg|=JghO_cJUwpw~NS&|1>*A=}&whwQjZyUrNlYQV~k zlQaJleg8$fe7ZCd%Qt-ES6TC@C>;A?MoqJ4#fMROr#}up z2mhWUa}((13KB7o#B9^TSld$4t1^n+A$p0?{r{kCM65ACsR*>mN{6C)=*@h%`&iEM zyq>Zm$)+hyYD<3Vy1ov-u@X8*t@M^S-Pww(R^-KuQoh)i_!B!LT`Qu?g6G-!fp%X+ zp^sR`nPlw)G+E4QE=G|xjQa+!DvyBBtPo9VO}3W!dSI`o_$Dnb()r4sb#Ud;tdcp z8w|M!fs!(Xu~MoE+LXZY*g>MGzP3V_F7%)}FQW{~w4}Lx_zRtRj*pSFN73mCI{g$$ zt?lf)p~Bswo(iPkK^ChHFR4-Lm$Ix+ac4!%Z@E2L=n9*j_Vkuo@)BQq2AO+{2XlwJeS%`c&|(#gEGF8UsbXUR(o`~W z*vg=3^u7_~D}ZMQ1+@NKk>7F=+&umGT#P+kZnur+ z-7D*Tud`x}`!#gwB)jk(k7y%#zLfIK-yoqck$%`&ny-##+I-gm~0arQIY*D2b-eecS%@L+3R6)UmC~q!TVBT z>}KpmOWIpmWKs=X8$q_p_*#I!8#^JCawJA%qjExb6nU1f`y9T+9*7-{LsY|`d$i$E zv}`M8sPF$;I2ZecJggmcVN1lCb+kKXiCjUCq5?|b=1y(hZ5;4-c5Vls_Gf)KMuVch zSALRE+Fy)NUFP1W^f4O_+^+3+vOG~m`*)Ti*0*e?F+b{MLff0CY||t?7!0M$X#YOE zU&a5K2q79mkKBB@Gs&99SBAJsg+*Auh0i{K6qM29$bWq7mpL^0Ag{G_>Runn+-+e? z_py{4%me?%D9k)wb$xme2>yu(BUUPmpo2p_=VMqGbErb|uBT18$z35WFNabUTvGu> zYoJs!^4^J6dffAy^Vz$zE~8`*r^#+DBaxHH;iKpqd6EaTu%l>mnYj-!8n_WX9)r-k z$=lQVQ_cAMbEN1WnABYCHi8wODkd1m#&>g{CbCDd&%h(*tYl7W$EH@~%U#DKJZ;VL zx#W%Zp~}LBUnLWJotQM%s8uG2nA89|wIti^(5z3&pNdh;*(s_2%JKQ05#!$5 zQ1B}AB%)f>c{X+%FT1?`^aqRyLIOdWa`ohM$$is6_#eeZdZf?rqv>u6r-mkXTU$(?6V#L=HSrVNSd90Qzm?&l6zdVUFzaCe$ z?Hg-{CyFPhd;Z68Yc83b1C3wC{m!1ylY~AEzk0!g7x?te#2-2M-dpu#oz@+NIRD_( zL6k}N{c=|AG@sXeBp&s1Y)wZzXhFU@iHE}PYC!@TvsA5cuNefZLGGH8k-j7)>IOzF zyf@KpC<%zGdXS!OKDA@7o=(}k51`r7RNVLnE^P749r7i6Sg0>??hW3?tL*h6_!ZUE zve3W6`cWEAg|)eh#>DQb_rbs7@aJ+zcFA%t=5x(P*Db7ZLP`a zjYe;i(GFfWLE)oxZ-qF19A99NE8BTq6Sk`#K1_FfHQxV???uUWR~iuY(FgDV!b^(^ z(GR<8>@wC~&a027J?j~wa;4c5V>CZ1b|4isT?VvO#rv4p>5 z$gYH0w>s+v$QK#PSd|d9jbm@h-%$P#xqx%LUQs5q|s$XU2YH=kYiV9>+YrEO0!JSof^^#3=4}o*1hk zVt=~*`a2ijN2KOp<+5_^_hez~#_EfN9)T|%ojbu3)}Z26@)c{D_JI6S94nR zh>6yWeVuF$?+@U3J08R3Kfs>s7R7u{j=pinb2QlC{UVq}@ z9;moT>)+>@P!WbJ4lKScsS>P?+Y{AiaH=k-q7Pjm`2ckJfED;G zm3vu7cTRhqgYtXj23N4y!$pwYj7kjl{aIR5&)GHL_WxG+^rcxb>d}@qJxxzK(7mYX z)C|T&Mf?2F>sody>i)*6rDG{t{x5w>vBzi2|o2eB; zwde)!gXn4OKRv_mhiOb2s}So*(s_2pP`xrKx(}X2MX*-zw1oa;(9Z-PFOS|<(EEtx z`k>g8j@Rdb*6{R_KHVZ-$;)C#{^fVL8Y3%LL+x8gXi+@Q>3&(sS=7eJ%BGaz^G2=>b9GQD6B*l$Li^c*OVIc_yu4HYYv}R)o)A{Nu81UNXf-3b zPw0D8SE%Z|>U!`9dOS={nxj@r-T?<053jXBpB+mzrP6yg^YCSS3}=o;R1nMLC<~GEPpU6zz=J%Zb&qcOlx96zB`Y74xi5LG{aZ`>Y6y+}z^Saxw<;j0hbjs?U zr+H5MdD8n?l#?VP>8@9iu-jl_%ui|P&i6StYU4KN8`Q+^f)WaRh`>X01_1t49|K&JO`#y8VnL?O(meSIOz@7W>AQv8AXGYMixEp(DztaT5FF<5GeHV(H6KBp$`QHyi=-b^P3oBk< zu6{o2y^|Mno;2o2>jzCHv1034w%83fR^I0!50|6SAvxt=O6eq8> zq0UR})nwW4#i`YCE7|JytjTruT3KZ_%A?}q%j|KQZoOd{^P1WkIenS`{58H`r>*r| z--YD8C8z$mO!`E5f-d}xUgGc9#NX3c*N<5L_hlNQ^4voI&xYdzWK(K+6?OKFWFa%1 zx+oVC>r7(Tk7IauTD+N#LT6z>#4E9vU*wTz(1KB9av*H#!8aY^+Z?@H1f62l!(wu= z1OiP;wRAAc`;>lk^!K!u_eG2DP`8F}#l&cpAXPheiMdd1d95wk{NZrwJy(xPAzRd> zn2#E7iy)?YYV4f7&l4~D|8_jDPPRKh{I?;Z<2m z;q+8EA8Y6jpvNf`+U)ad>}M}Dd6bt{*8l%o^%i*3igY|h`s(v;BS&xRaoC8Gv1T-4{_XCbJ9X9>*Pr)oA6br-%s;sER&iM24FdBzRw*suKeW65?r?ip;&QC9aZ7OV-mYsZIa!)jHL8M=csml8|d znl>Eb4{*n!I5GzhW2NU8{QLEu^F2L?_3j&C*gh8VPj@@1x3LFR>{D8g>^y)$UVoI+l-?U*Y`^Ht2g2^a}|(LE^p>JuYG`zeSN1B9nQZ z5I({YRR7lRu~uQLo_#NV`jn(ihwJZ=%J)cBSjrelTnJH@lD_Tw9BW&axZ^lF6cv?X zME6Bkz2p9q$l5Ee8zBCAUiS0_ul~^SdH6htE}wx03c@$}#&h=bD1YObY~j1cIC@gh%dUcGyP#zFI0RAMH{(GT~gkeH}V3x?ka+A zivGcoE6Lgs{`Upa8v8ZmW2YZ-w|=x^468JmR&1mdSrT8cXoYaB6|U!?k$vgqf39rq z-t+iME8Y81pLffbjFkr&DNp<^xsLtqUgsmsguQ!Y9*S$v$J(7GG0(W*L2C;#B>u9` z(F!@u_xbRH*_V1EtTNhpi#Go!O8kTGxdEk?u=X?Q$=kH!MTp%64mD53$}^$EScowS z)#pQzwd8&Y+RKe6tEA6OUYow&-q7`N^&cA8hL;@cfS=Lg_}5$OO37YkHS2O;@@D&a z7PsoS6wcMc%@L&O5V^e%HNp-K;tRZQgy<9Vw3cb@bo3vfMs z&X1b+LYVrZvi7L@B;0ADXO-bdSx1WE;0;hI<_ktOyb4geI$l=gZ#)LedwEJTNY(;{ zJGobB*WN-Zs*#WKtni(#sVj=>C@j|P0)rBS~SVM7J1S- z*Z$<#9M?aG+I6%iljmRK|5{?!*srVxe0x$qVjta_{I}Rk`Y@e|YV_f;j$n6&!>1R~ z{S`F-f-L=QRP8$bN+Z{k@SqCsvLa4B1F7dYXAUgtO4|y{9c4r1>(IThd%O%aGI(B8 z=!-q)W|PuUu)C>#m)8Cm)1OVRdhvc^e&*%o5B!s?=??X9sRjS27ae_(w-oze45sNV z=wR$P)B_)f`##CjKTlb%^>A}1oQ_$Fk^MOC|EScG2A`rnQ&BmLc4j6$2PGdTc`aD< zdc2$>=Co(xE5x3pKkG-V4vLv*xl-dKp4~TS`5`2ES0*Lur1sJB{ye9FdiSh;_1EXY)_Xm!zYkl-+?1sD z;-mFdf3=PE@%N>ts|$M|d9Pz7%w^82mQQ{eBr{I zaQ~I8%SQHd8!LZ~zZWtbb7QOU#%qi23b8eX`0g#q^V9U81zBq?8}cm483~U@u@=LP z_eZtJ_q|@@g^VWYOW?u`Nb(|G9!=}|B=j-T7W*Zg z;-~+LBR`{TrW8^&fmY9u`%bB|hIsNQZJ6bX4|$^R(4tDDGpZ!?l53j=>#rh#3+YZ- zwcZ|tFgf_#pV0Z})9)q?@cfQAw?fi+6 zw5*li9w(K}=uFHweTZI^a_zlvJ66S)(u0V0>abidlPKPR@>&p$ZeTf(te&3lYQ ztYL%4@jDlix~Rf?y}rkOl8>Ns6`vy?6uWts(XK9@(^Slxft`ygs^_&h7c{-g^NMT7 zot_+foM(hHyGh_S>%z9;+I)WDyCi!#ddBX6ANd|A82;#&=sSi7I>754Qom3{wTQHC zVh5r!QtZKg52{y(m-qTyNz2O7(9Gz4-b|1Ln|*<|euG~h)`n_YP>i-l{1!6+W6gVG zt&7O-2O9B{d++3nuj5DT(VnO+ayj4fdOC6&YhOS=E2X@FJJ7Eji&oMdu5-TxTb7X* z5o4x@*__Q{g}>9gkkrAr@ED&aR$J$HtROF?pt*)+%qo5coma!6-Q@HS(sGP!ex1V5 zyIpmjhq9c^4}wOIK!l;j(ye6?5ADP886>MD8T*yZS}%6^RgV2GwCzX2Bct|}>h7mS zbH`Z7uUNqM$p3SsA!ZH5+N>Cdh*;=qo^1~CP%B8(2Wq}4@;Jzz+~oP0as3j%CI`Hz zfMa!2KEWoO*vvOPZq)P&{mzFbce60Jup%XxY!c+TA)@f)QSBo*FlUo&A+UXKGXiM1CswGA4z6R z@0`5M-brVZGtH}9p3EcGh#i6LoJL}s@Vp;SU+4p9bUw5I~|QR7LkR_O&YU^cq5Xlj*{g`b3u}j z7mmd|jNK&vGgz_H)wxMeC0BGp=`OCQ?)Qddst?JIT0gM^@y&R9FqJW!$Yw3k!tCzz zm@H3ym~;n>yV1GTaVhqoox-|?udsq-^d*O}v+v8ip$2+h!kFfD5dL1C_Y)+gkG?L^ z=a`38#JO!;^CHA)4^`X1(ifpz>>4r%|Jr$86WqTa&K7}$C7l2=64h=kP@RY%RhB6=S)doCkUm!r+Usr=(#r15Vy;1-_1|K`fwj#?F6 zUk`po<&i2V5vy!Vz=j+o{s7(mOEjJoeZ{U#SBrYFhpZ9f*3)%gEmf(ik53crrE5>lIQKW6M4K z`W!SEg%49)vjEPw24_T4!|ZuhwB{^zB3Pda-A<*@j2NVh!PMtpER< z&40t+Q*^Jl*UO#}qe`)-W6W^;3PQygSgdL*fV&TgQtH8qknI?4>&!FjpcPH8&R#YnE9t4E1r=y{?C_MJ!wVtD zNO(L=Ec&f{$vXIXUcbtqb6xb0+Vi8#8hKm%(3+JwMh_Z^WXs}v>~{GJ3`{qUkwc6h zxcU}pt0Vd;!pE$k;$tl~r5dDql1Dj@SG^Lo*TIUI*B3dF2kCGlXw_WHV&&rvFeNij zIFq^{_N&H`arCewKHkO3T4U$FCynm?%yKM+hEa#)DNnfHGjs4~E3uiKJpCEcNF#(T4smB=1Szlq{6KA(=h>WbzizD#z=M z-1ryhafSYs!-2+drZ0;f^$8d8?`H5t-}5PUcX@)3*h;)r*O3QdZFSyW5gfe5rwVYm z5!4;Y6P@Zl?}_K4o+JAoqfUKfc-y;sR7bBy2KtG@pM}6hU7y>1Dx=c< zo)Bx2>iDIV`&Gf4qGGd{Pyetd#m)t-pjZKRE9McT!R@1v zSl?GUg#j5!{4z(E((hHIC#oX%7TL6x@hfO#I2$RupL9LxPNj^n+$og!u|)GY;{?#9Co&K$1QUG)74(%h8=s*le_NJRx`dkcxX!o8x3LF_0O)uYbx z3HMneWbJ<1%kXkMy;}^+W|8?1v~M1JGQ+3HFMU9Z7is+>l>A>c(Bu5^*as&g%N460 zPHF$&DeD_M@ol4tD|s`qbWQGs^GN{d%%d0n1sLwUQ=_eVc6M-AM26$$zdvlZB*VEU6gl ztlp^BRJ-m)yPLG^fcr%~oX_2THSgd{Sw1^m%u^{zcIxr3+LNDpxY>&S43x7Nz;haI)a-rZFORbp<@k1Yk;@pn zyBnWM@N6!T?+c!pUz~MO&gE~~uXYt1@{H{DWQg+vKj(C;; z500|l32VvjX5m_@HeG|17p4Q@x$V-E(PH_j&fdz)%0M?;lEqPE)rv{nt*0%wvhQj3 zKiLa0X2{*i2qq&h`IY@ItBTq`gXL>UZ8Lfsdm-;bzf){M8UD=2dVED|@xE~DLlSZQ#=2+w)ki>$&SH2MvVzSY{5u3JKm-|(8? zeslS*Ke=aaGxG|gPK=gaA!f*$nmP0f+>h+S52%qzKQB5b))z>YtCE~sKUlp& zEB`>{9VB=o8T}L&zt^kFSdAOtPwciB5x_KhS`?4BCErP3mh3HG+*Ho3S$cNT)qz(2 z=$x2YToZD>%JwgSHnGRbAF%a+XmA&~Tu#mwkhs-+h)-bAC})h9rTA7xIZI-W@!=t9 zr4!?a3cSv^#$1_{dH`Ryd~8j|uKyp7py5m_%o@3~%c{J)A{7Bkxx@Uv$^rv;>aEsc!P zoj0J~FtR?%k-;RtFYSAYFYq>7zL;(-f!#y-U7dItJ;+}~R#AH+Dg@4U)kpqfy~|vv z5o5-SoVl6C93W|j`J=H5+23UE8s2zuC|??y<)D$V$HEB~G3shZEs~S+Kbc_nP4pr! z=`RA)i|Ttmy}Z>GF)o+QS?5UBQBuEMK4?APejiR>FiYjvR30gI*R0CAmLaEE&6qoz zlDeI!lJM;&S7nm*J;L|d5n%@s3KdK*i)>V$D-IPpbqw8sbT3G#*PP7dm^q*JzXtTsuk6uVIs; zK4+|ii~U@q-dA1!*Yi0tcDF->SQB{?xBn&88Q^qQeJ(>gYI>DUWeI;{cTbavzxDoS zt={1k`@YQ4(+^3<6!dr(Ef(oh)L?nnc+Ffnj~QkLbkp1BJipj)u|3=PJR3OH7>%86 z$zNmgG=zlo_a1dUALdQPK4UHQq`lv(kdp!;xEpEdb@aJ}xMcu3OdwtTwcvT&dWGE_ zgSKO|YKVJub^ai2{7|1}L+2H#+{YmrpF!`#H$S76$*<{el8KIFq!Y{0Ipw3oP9!nw zs1gjh5vJror*v}-_J|j)Mdsx+K#!_8nHO#H;Zk|mMkTLIm43ij3GDi?04YQTh^_-CLiA) z7S(}WF<;c#rh=G@rACTFDu$*=|oGPSD}D@|km?+icdoflSaAveMl+#(i-0W^*b3O0JWC z%t}(8biakX;WIqs>TrC7RxV&GV-?OYer!K&?}}38^dmbIDBwtSRE|;43cR|g2U8hc z>grolI9`u^sKC<;L>%af3IE=NzgxT# ziI%XqpI09|8O*1ig!XUYP-i`g`FDf0?=4vWE@bb@@9vCqgZS2CwRjRrzpT}b-S1vU zOTq61Dx8#=i}k71pm*7n25w0qOpMB%Hv8!k?Z1XcwGC%KrbR*X7oh7PlUE6sd!~VU?{|`UqZ5DAX zU;R~moQxiCLY0=TZKkhJxxNm>z27}!UG`A;(+~E%$HM%@rzwihHQ1~+xc&l}91LHg z24ov@*IfVFlktHm3HpkhEGLyioimBNEMxhX`hOl7UF!Q(G#pNM`^rJIHeam=se9b3 zGwFN|*J9VIsFv0iqQv~T+tDiO>BNpM|FWk4(Z!=Y!9QjBqE1&<5yE!T^)=fy8h?kO zLsUJOub1;#!GB28_4Ml)+>0E0%nHm1^`e$VC2?^6v{Isx|B{cT|CM|cKCgk+CF$u* zxsjytiY!)&e5~(}lkwZ}=u*mOTmn;mU{TMhiIS0S*Ya9w{OuyIDW7?A4<^1(YvjFx z`2tz2JUL>u=2pM{0QJ64jnGY}TRk93E6-}JpS4IxHJVq26)l#E7w+&Lb#<>GZ~xov zCFTRh{x*AQOH>T_6aJp&1az^>JF?MXt?ATv87_$y;Z(k` z3to2Cr;aJQcaVAL#IpC19c|@PUDS^it@%9tX05naOS|&-2kGHUaA5>qj)WAQVR20y ztHJI^ZQ#LrFqA|L#;-R;3}Z-24QLg6DVOl{W;~%rypW1!RhL)&q=b0LdRRQ&MDAmB zYmC0N7AHNZy^Y9!W88a4p5i{bk)4*FORi^!V^66Oz;Rz z`KZwLD&KuF$)8HECb_eDvu5|-%r7W~IvvUMGi+lcSXND(P{u5fo6=qrVSJxHHN0p3 z#XkL?$K&YgdsJAt*7e(I(L3;?kw`0-7FE@nV|wrcj2;Lm7&$bI~WbIB&gwd|al+?*Vwep4@_Vxv?z*^tbj z-*?gQQgr_jQr<`_TJRs*>w7OALQhY8Qlv6S--hu-SLk=d{s&pU^=$uQ)E}<}llVwK z%8vh&{uO(&k;NQHT8_ixr+Fy(_31JwTTG5@4v#E$4ew0Lo~N0k@wyM&Qi`2D;jVAH z?~S~eACi@=C&;U=<&Naz$zjQY$sx&%$rqDVl0*H?Nehif-%2_nV)!0F+yC=U0 zr(S?wFKO%Bbm9f5HI|1J>#bMO{9!zR*Ni<*r5&H+{huuI_4rc>qL*eJE0FRMs1UiL zM&!RDnU59DC16U7&)y?4kG)4Piu8V!6+X%XyOjp!!QTty^%N8r_|$!}3^7undAydSp);Py5-?tJ>tnorf*{&NG( z%6ywQ_KNSl>FtwdEWOEQE%4h9X_?J2*uj(fDs38@{~B90#!BE9tdDy}HG?+%gpq99 zTK>Z+Hg5&o8V|=Oiv!<=0wee-10cf$*zmORzPeDo5-h8q8gJpUvGyIy{p_Q_7l2_UHFdo@xAQYNwZ;28drcMe63g?(%oMd?SGTpPp5~k zi*zTlN0A?Y*KZ3+`VM{gnwC!1hv6t0^%olHSvCGx%xt@X?8Ht1QSZBl{dP=8})b~T6`z&kKNwu;Q7_!_*3lM zCUhT46Yi&JcR;|xt}5oeBorz}6Z4ST{A_NlKN>~FRGHw zAaiqAo!D<_Fd6#P43>+eErYe0$63Xb+K`PeRaPB|ie@g{&YoT)A9~t#NxdnT*pt@N zJegNiUmaq<%eIMM)9RSV{;=9orRAG$l4-gz@uyl-pUYt^V0S-Zb>|oZ8$ueNrSao= z8SkLqSloY$Jbb`{jlt0#P_7v&M-}$4X*Ik*iKkJGD^`i0h9j|GXaZ+qZP5*K>wo(e zd7UDu41MhWbQ9^Q>+DXf=kt7}5p-j$_obx#l)e>A%(edK3*N#)<1x!*_7137e5Jh{ zlW8LpNA>OcM8ia;M7cz+L@|3j7E6>(6!JN5;u2b9OVm`s_VGlWL>0AXFXvBpnZ5}((x?uX4h zy1`j@B_6fg`R!EP5aw9duZbBL=$UkPmr3m?Eg2k zB-X|kK)dW{S&f!W<_rGKFT5ggO#3q@YHQ1*cC_rPwNEFixqG3+k2tkn{`*5b9^(B) zInLpv;#IR3`-)Z?xkFPHt0~X13~w=Zs12|DDJavNR>s~&b@l2=_|$`CzZVil1+#p- zqE5c&Q#0z1#2bnK65rT~bD>_gNSsqyYPKiF-J+^zUfITSxc?FqID|TPC%&@xW)8b| z7EgSo&6}(&{xz{6u`)3bbxOM9Wr+D|L(6Xx$fHz?D4rq1QD9=KY`nuoy zvBl5Aq?xW-g2u6v%s>*`gOv3_pNS;yEpi@X-LI0t(dgHMKDL2M9ie79cu`2^pt?A@ z7Q1!7Xs3c4bzy4)4%6g6c@js&Ovhy?j??B{aN;9g&rsgZ>*A;0Vy8Ov{ziCk3ty+Y z5we&C*aoV_il5%*jhwUl_H;XPkFfvVWNRtE6S-aP=w<2OCTAq4CR-=Rux2aSvr;^O z1tPqYuDifTxq-c|$%na9oV}MNT*9LtD!2WBr{2YPC}P&@l}1`uB>V9;MkgoP^ZU5n zzq31*Iekg;ygTnszQ#T-W@>he%d=V=c~$z?e))hM{aoej6aEsOd&JzMz4k=<*=vbb zF4oEuj-~Tg=JLN<@lRS9&wXCIpHCJ}@4$XPVi%>lu6mhYvn4q``Gx*)<5*&{}<7n>?M|quG%w9U5T$GY+&mwveP=cTQe4qrNXY0IU{l8Y`SFRj0H;nMy~g_7GY-I&~RDMRwlOZzS@ zbfod6M6$}IE0Y5+U7g&1sX#J!vPQBh;Z@b>#=~T7plS&dWZB-8XPGU3I88)fT~_UD z_a3M?h`MbVmqn=Iv>FM8T*`nl)vNt8I4DL>*<{Ih$ z-3V7%V@bWBduRCFnssd=lNJ>dFE`HdttYW52xqj|K>-L0<^0VPq7^T|7Lz~N$0mhiJpAoo?6h#bDPSI^maUE z6gg8`dfAnp(q_0nX*qK;2@HQWG zHY@Q3?|m}Fdx-y@NgHBb)p%(5Gh96ZHMhaS`FxOhQ1*FV+pjXqHPLQw@|N_^$ip!b z8T)d?n%mp7D=C8<`vO%<<*GZQZ(qO8^(`vv#i&&QI9dT(-_3HIN0krcTgKpHcibt9 zm&eHd*5oF2BCmvz*W>FWFl>{&V15W&0oqnUudaNFh3>XMeqsWz_e;LRHa^%v*5S5< z`M+{XRTB&OG@Im8xA9@Vv$A0_t2myo{%Kk_zR^&A!6S*^S?^|A^D}R5FwN*Lj`|Gm zBX?O1P3N=to5Zu9@`X0DpzBa)h?dv4vL|<1CYwWr?*KynLZ?0EB)1E z!}Jx&5q!M?aK5*>4^zq9*XXdCJy=EVV@~)*Qd3x-H5)r}Ow95-soE;?*^7z^<5U;K zW3e010se0$-fD4lE2^#8Nk?`*Z+QCG<5<)ds;6CbjFUagS~f~q&=E2~Z?NnyIy#B{ z+JinjSlH<}KZ&2Zn1%ep`xnkyjn}{O_b$lCTyX4n*7zrqvXKpp+~z9wa~I3H&Uxe5 z(D9DP9y&wF=o5V6A#C?V7Iu<*ze8pQ@kNJ-fM)O=WA$MzvYCO|w%pwi3GaMS~BW zGuPb~YTpr0EzSdMlqkX5%a*8^xR7=~udcbfKI6R~FX}OzzmxZs$$pk+(;o4(dY<~Q z_2g9&Kc|&ado5pLqj>Hwv0hrDFdy><-hcdkiGsh0=ni?>4$u2uG_g+4|3Hu8iIsAg zM|hK4%@?525bqH^L8**tC^)g&MNY}%dtpxYB)rj_M+ zR^ttpPh8|(opS%Hoqg7vh_A`@a?f2aAH4}Lw$tvfaq>O9{D5YEN#j>JHXoOBdWMz+#5wb@%A+q<%UMVZP zGDB3#D20-d3Vo9;8cHP^D);$6uk-uoad*zS@6Y}Dyx-S&U9anUFaQ4#3w?*?VwdwR zK6?YUOvA2*&{>?vF@=4N!T$Qoc>@ zTAcye0@GvlS8bXq06j9pi_H8gcIVFz+ha$XpUs{5+Bi~V*0E#vr~0#8G>)jeS_Npm z)-M;`7QwW|7{iNc`Dsxx?p7F`5jtK@R!@B|*#x#VHU1k>xFrd6w1-AVXgx};X(3s} zIn9dnEdL$4BaUX&!t(_l9^G7FNtq@SZ{ zb%?$X<^hwT_#$$e2vg!5;m&Nhm(TmLsyQ--*<@RXE#9ZrQ55@lgtb1w8fS`~OW5`R z7W*9ebW~T!X@0;-mBYrJ7spB;UXoNiDIgvN3`-{!Js(O)3h1SgBr0-=1>k&TM_8 zmW`Fs#Ljl5({vOoa8DU~`;MmmG^--!4Chhlyr0g_iJ`HZ(IjzX46fgwyt|21ZSkI` zF#SGo@jdN)M}?#n{oRfCWY&tdtnzbgBTi9zG0k39X~Ceh`9nv=^U>H$9p5OeZ+S)T zC-AY!bidbq@~b{g)x$IF^x?#olrD)cy>_V2ABB$@Rp@_(d+W@(8qZ>%hw@!$ppkD> zr&PG~cNOWZj_BT01tiW!=|Y>0^x{k3n4~=`uz(-5 zy0OuT_t;p>8OfNqs1}o3jpBCk=yQ9Ct|X_)yrUi#naUG)m~*jGU3Vs)G8UIzL1VjU zZv|V9if+ugm`wX|me5q(`c<4_IV+FK>N!>Z3;KRhUoNW_rsp9yyK@F!ml@LLr;j|m z>tSA2m0vx~t7_2Db95Jbi%+1b>HMex?Zh0vh!zcbT}c{?v5tx&eM!12#j2b6e1KTd z-Mj7FzYokEN(P@^3w1iEL>mYuui;gGI$OB+3hm|4z$+@?$^U;P6B;?x#8y+$jK$s;P^ZhiRN1o2?K-?ozHEbna~;VcQeDJ6Qci`XHvH>@hHo_0_D$q*3+d_wIvIpp zF65u9>1sIbb{FA$z`K}X6DPFiWZf}KGdmCYon~Sl$v-3+=Sti|qp^>2?1p!T-sgw) z`Q7g!*jk7c6oV5rSVRYQG=$AfB8}ddMeKZ9kkn#F$Rh0Oeowv6`#F7*j~!KmnZ2|k zcBrZ18TrijidD;Z;~g=lC5IaJ&0be%EB1em85bwCEV9tgAm>GzN^gDf-|XltO~x68 zJ7Md`d}agd*&qYh>H4>5em2zT!;YS?|5aOKY18C1)5N^VvXu$&z9sCeEM7h#v#cnG zEDe*J;spc5&vEk2Ddv$)NG;*cl|{rFGV&*(bx-KM1dDx}=f?c0n5ExX3*uy?JLH8K z#OWW|d(1>VrzM~GD^C9UOuJTS?Wd~ZcN-BbP3lqOzN#m?VfJph>bI_o6^OAL(jfAj zB6hANugy^ZdAa9b+Okxirs+=$NRkVRwDJ6F=wxJCO>ZIJtZR(%g4Qn9?wEJ~GroPR znpXkwsfAkED^O_xRIe?*ULoBRWV@3O4VA}L5&vRrt8nTf^`JLYD1Ma}J(8BA=QR?S z+3ywbr}lofB(H}=s2fNjBkaB#Vl{`-lk}n&OH#q0sf^|op3=q{u88xUzEKCbJ*B_8 zv58~E4ftNX<72-@9U)MnewM3SK_#EJkG`lrt?=~Hg{1e7H+=&R}*{oNaMhRpouUcpb*?(T@FaIp$0);|J5>(LlPI!*)*U z#X(;AI(zHSlG=y@G2?r<=g!sM`4DWi@5LD)N%r>@q}a#vj`G3HZ1F9heCEn8VE;Cm z>{2Mw9=0_Qb)JSEtvq!c#F&fe&f*aS+??g`B^skM0(nT-F z;0d$LquivvcMuQ##NS`i(P=;TLEYF1Gfo)%hYx1QRP%^>IYjpon0=h~aGVal5shwx z*@fg*u@n4ydEFFPT^Ua(jPJ#&$~sWK6y$rzjDpxPxum%8P#TYF!3LU%U|$&h>0)%{ z8K>yJkCEmOk3J!dH|gU5z5PWy1;mN=`283$>}{FnaWQn2oT-YK5&Ksizk)i zGFUW@or&+)(r$XRN_&@Lf~)lPh|0?EssVpG6X+KsYkOsTleMjxco#c4tWqnO;_5c; zHr#h+%V+1~!XM&;`#o!+D|*B47!7$D;=b=&OJ(29MZm)D^oXbT_F6B7ZWOs=zl+jv zxl&ptJQ#x*3h%n|muKmuoP6dX(k|+LT}di-$E*#(JIaVh%0-9Zp--u%G#5K!9cO7R zYGyQSq7Sr;yDe8Qy%)t*;LFFUz@Xd^C2!8zI^^=GT$Cp2EG((8dY+Iw70>nsvo0gM=Q( z$zU0^8#{tOhJUtUX^Ukb^VA6ndSa|DDlYyucXjN0 zw?I$xsxnUzH2N$t9uNV#5n@8&~KllmI7qE74AuC#Hf?PRl1WSY+JW3T#B?lX`* zZ*u2jytX{=iaBHl&AeNxr!S~(?M`_p@omcOi5{%8pzLD|&97EFd!Dui8M{Ts-rKQ0`8Aq+-M7AS)fMgdlth+!ZB&tY!@s#aWUf2SV^weZ<~i5h zoY;)F&QQPU#HPBt(`5IZO-uh*AFP5^#F??R=^!H%DZ~zj`#DW+Fu=@!XR(r|vh(6T zEz8e4$r~Esd-p?vEbQWLT=72E9V?8Ul6AE9uQ<79<_BG|p%+?82JL8SC+qJ;V%!#-&%OiEG&4E{#2shn^@Rc+28^AkW1U6 z`mm1_(zAz>#+{3(In^>&`n+-De5CyvNpvLH7VZ$|X z{|tF!wMp1P#JN2BS5$={_O^{(sBYEQI72k*YaO*MuijVCi+)o7E3!yeaqeI>^37ON)v|3ESO z1>YPZ;*5aCYhn0y-&pGBaQ*M-DFho}R#q=Hqc^jjMFREzk1$ZtfrR zM&pEu*jr(==-%C!S5x)JBBYcTm*`A_)3Ben*i)?8iCv;|X#3-=_h~(Er9W--JI;EH zK3+8{6)U5MXk~nJ76#H5qxb`FJ(SFWN8f5}I;T;;n^N}~cYVW1&-?akKViiAqB&TZ zjYr>R=I2-1`ynoQ9&^46E6fM4A}@-4+G`uFD{jm&a->=?_fhSA%3WjKaX-8wc9m{N zQaxBx4+CVsWc;JAf4b{Wo_XAz_tD8#o;TmqUZahpnAb77+CVF_ z+3$<6c?}J`M>p#|DKe~C{_g9leyn<+pVRTpH9j54>Z`ExeqzdA))}*^FJUBaU`c(k zra>%gyb-dgaQ_|Ji4&L3m}C8u6$Mq`QeWDMRRe)~>0#Pg)}4XB_J!6LRJ-#evYD@v zQ}zF6`1BSW>MzFCfOPl6t=q-X3%vEe)G@wMEb&ju5c4it89lg1J!xB7b!nJS`l+tJ zXMSzQ#LMQptb|X?)WnyXld(O~B=MfPBz48Hk5nf6xPL=*Zu+Om?KzYU*8#{cO7AQCI63ct2nc3FZ7JF zXS>4oMJ#lpF`he8eoVfc`a&{GYG--Iq+~sI7W?#Gg@n!AcM{eUV_2_vZ}x};v-iMu_lZPl@? zsv>i3x@@YdGga$96Mtjh+S$0&Ncnv|jIpr#N$dl#4$uDBr<+9Ny`uO@f9>+_47M|y zCMJs~Rq5t_h}W7P56k-RFjFj*eh$Km4_x(@xPAmTx;asf4c(v)8K*FPrv5sB9ki95 zG~gu<@`!uMco?twm)|^0ujSPk%8N;b^{Fs!zH$-{WUlR@;Uhj1i-z(m-F@ z?5j=v^`@a-)%Qv4Z~2avtRbhEowI;6&eO&|F}Z(QHDj{c8hC3nmLb4tU%e%AISl3>FHRj}1 zKZt*8WiKz$@jSMYC++5PnhX_XiK>+z!AETE;D#> z>@oL1!n z)PKZ?*p;Lf?=1nLqPF~yc4Q^3Y+esxsgL@*7^}RKd}6Ni?X2To_F9s?mSe%yX`-p` z*CM&tQ@adV#+i-x=t&8(ED#pxvj^BsCfFBq!|zC|Oa7z|x(hRTQw;bGQz_+Mwe_op z{@21Xs(3wthjvTjZsln4QEkfNX{l!4UeBYm!=g;Cj@`vRccn)vrAnS4w-@2N>G#oA&AmjGA-;0)!9WquNS;RAK$Tr97bgF<3~5i z;;+%pbRyheY3nI+lV$A1RR>S136bm?O=1V3!X`cMB_Aq4ZjqPv_t{p~e;)Hc<_3JQTy&9rXiDV^puWIDY%CeZ{z0)H ze`)skDBZ;AK+m(x7*~y|L7Y*$kfp!oy=AQM6`w37=}Ej{f+sD3ziV9a5>IXmWn*Wc zSkn}{;M^(N->ALUij|kubmAn!IFaHEW^{&y{E=1_`j;fniIs5%%6azs@&EsKOl538 zNo^qS!w}_r5%eP{yxMnTXR$u6eOk8Bh18#cEOl6W6ZO}aSJuwwUGT`))Xv|AX>oqp zBDJ?V*7RRU?lf=ipXB3a#ML#|tO(oq)l9tiRbAguMg2mB_5q#}+Wx@E!4;9ZG^~AC zU$XJISOxL{n;)bST#x_cNWGC|-Q-SpuzT%V?$v%3r$^B!O@wximmnV-Wg}HjQ*k^0`RGi6iKmxIz&q8B7V++rJSuJZS zroWav<1CPvbr$zKKvHp<VT0s2Xe(U3kn%e)k9(U#W<6P5?{EB<;M#yrfZ+C|=(|u;;i@OvR zKPv0TbM(br?r*%K5lv*2z5XFSWp`~QJpWF%aa^Bvk;Yd2iBa75-0Og6{f}L2)2Gp- zJW+ervXQM?`JSFF*Qkm9k!+r(v8b4~fUb|H#rK7-naM}T z=<8^`9wxULCc_yez71v(<&1gkPc~sq^;z3kvm|qP;v10rqEU!{`ND3RiSg(Z@_WO& z%mc~N?p@3MCVA3&64|chDOhq@e%UzRuTg8@}NHb1^`<=z@ zg#Itf%_1v|b93HcOP{l-z4Ww2RC$LNy(fO3^>+a%d9&wyW!3mTJHMVciz8`Whpb4v z>7jSA!+6ZG910I-iedBgVm#*XjL%x>%S&S3Pu2ghAGwoY&LXd+iojoLT$hOp8^da>}g4JIrm$pSbE?msP}% z(L>DGTdh@{-T5AT{aaWymsj>+(|!2sWYK@N__B;e?`JP(d47zZWim@Qvs&xl{v8sx zW53Fuu--qdI=l{=KPJAm)zjO_XXcfqP>~?I*U#_gICe|r2JkcjHBrzt@(Q1Z5iL&OCToz@PrpdIrTqqZ=bTdZ! zE8PEDru9>5D^=*Li^?C;{fJ!qnfD~qOa*>s}aIrDEn!@54D$v5rMw3rvH^g^;{Wqj^=Fbh_RzYZ;gdazY?43^5 z!gdyF!wGHPu1E7=)O;AQj}{W_K6Z1;B#Ok@k8^S6#zspki&{nSqD-neeX^856wHbklc z4IWiZ$pecX!QgshU$bD-9DcandY13xqkH({hcIoYd7Nuy)3bTbVki;orh1cKOYc;3 z-&%aB6+h|%)f=$sg5(w_;1pwP` zMGYcmmfx+V#oW1)yfU)9@|f)tGLy!vte9`7OUqF5<9l(2<_J$6jBCfhKSXLa~EL%pCle4L;!RouT%5J!@euW-D`L|AS(keDV`pdlT0>!S3?mtX1*9 zHqdH5i&*A4-7)?8Fgv%W{13m0%fc{%tD*!*W<7%FBudf^A>W7>E_VRlTR#D|Jg=A zC(Lg@@8A1$H;1N1sd{uY3ew1ETpRc3sNygXx=m!?Jzdd}{)UNbulPJ>ug>z$bNU_o z?ACzD6-Aw>-#tZw^>}tA?>&OORF!$xhs3da(T!wyALbG{#&3G{6`MQ6&yQgU2l?tA z{N#f8n={3lVmtWdvfJ6UaQTb0T&o_88Hn4&nM8FU&_H++*o4!h=p`+VaLhw!xD`1~)t z{2Xup174qCQ_J|zJdx^sKR+VXx5S)7>icnC^CPrhQWlU&6xz%h$GPWPTFFC7FQ?pO zuY!9Lzv*GD25t>w|8rH0TMSVf>m)bqBu9)hB$nV_pJ0iXwB{bsu`COD8WMEp9n;te z9i;YDCul@2QR}!DH@QLW_^Lbo;Eu7w?H8g%>|!4}joo_x6Sd>ywfycCCm~hBHy(4> z!sHlp@E)O)GGyPJeGf1$JKTIitBn)RN=v+J-RJR?x{2@UaZk!9)xVC3)RaE>$$-S2 z));0oU;2!{KTqkKxRkQMT>0(t&FRLmnk6>buVaRDLzksIn%F3&k2lWLiOxH+sHP%8 z6EbTF*^1*$*Q#P<+V_ z6WUyruVwa(YsfryH2)Mn9~DXCEWqnwTAVGOo>zUxlP>#Lz_$kS+RwD?T66m!!n?|0 z7)7i*Os5~a`TiVIX$Qw*50*grpWX2Q*82|qN3?&NO>D+qR>?OP$!xyBkm9t^>%1<@ zTQaCI+@k_~A1-_^yuO^aIyp18^evry1*KAW-(65B6Q9qql;&>p1h^j3<8Sxo@$^ZSMOu&h(RvA%jSo3FrLXr~hE7x9f8e_VR@Pm*da(dP;7; zmB*-KkI~o*Gxik;>ng{#o}rTwd~%TYI$@^`i~!W;fltZnV|<~MD`O|EIB~HiONz>2 zaS`Sr{&bHz*|qR1@IQ9XK0z}_+5ZJHxeAF=dDMBH^%K6Bo-7mmcki&Al3Ts0c2z`xsQQ*Tz^K{OnimNAU*{}=hfPMpvWvm=`_J--|`4zt~f{ zL|=B?Pu;&Y-I|lF_1pCICAK{bw!f)LeoUqNIE48M_Qagk9U;+1-F^?$qytEUK(~>@dQgCy|>K-JbZt6P{Q5 zxXNE&!OxzBRg)n4ceu^HqFW|fzNqdR`*0tzGvmDwH}>tU;y(An#>ZhwbFYHrp2BA{ zklsJO^`Se=VBvjPLQU3KT$Ld5(M~e)c9?uq9H;>lYXmu;fr~w$XCqe^gE(0+ntzim z?Q8Hno-`L99FFz0Q-g}rGzN*PeZ<)A?pYfq7J`nC&|xzz9*3i@;#u!_>N@tn9%tNS zyk!&SxQ#8xY>3%DpMt?HWC81O-w!a|_w;xLY}&|cH)EC?F@SBj=Ni9_Vihy6k?pdr z{c?%jylN*V{*Ei+6zTVT9y@Oyz!r|O?Y%7fGye6x=YGM?R=US>SFTCJ(;a?`k+x59 z+b>-4Ety~B55M^CS6cirU)=-Qw?g&Vd}uso5$CcFbpO8i@=LINwQn!-%~!nQT$6RA zFk7F7dUaCO>EhkU1>dHFHJ;IzPd?>&&-=zwZHYZWF5_Ie;8N7L&hq)q(0GR4cNe|u zi_+Qg)?e_`JF%7t@aC7&_j?R`&72zRfzMb2x;6QVwVIzMk6UAVtC$!gt~uF50Zgd`?bcI|hykc*9Ezm0uXTTiOfaXq}C z0S54psF6(%>-+9#+8&^H)m(G0@!_mSWQvQrWl26iP5x+g?Tb(S=Krm;`i zcAWVVV}0qMM-g$UF*~UzB0R;i2SC->!M7)j>mcrwA-T&?^nXzFXBHP{U{ry8L$S;k zAXXpjwiC4M0^JrvpEELx1NiJX_#c^hoW(PS{kA5F;ynE^y6;3veduQ{D~?^@zUCu8 z%Afx<3LED&{>S3d!KOp%Y>}PD%;$q79`(Srq`8QtEQKnY_iJocu6Ox4It3 zh|z{`Mdr_V^?NK}6|Ju3(R1ly6e*0>)0nl=U(d(FsTFkg0amtC`woj}zd(~XBWRzW zQTdsTwY2nZbtuq^bb7h(v+mMF4~w$DeC)51->Z^EG2W7mR5IXv>8+8<#Q!fROF@E6 ztnPsM5wT+W4Yv2cWLffj7*14YZxv~)0_$&1uD$%6NRO+%UZ;x{KHEtj!6m1V`m4UN zT()i|0V&6NtH;=OM^_Dk-!ak_`!06o)7A7bj~H>CZ(U3qyNQ<6^>;0PnODp2qPx2E zyo(P%q;ggh+fHW}r`~)eoqtDE%FiV4R$-_I7uUebILW2FOyhde{tJF{5Fi|#p2%veIou>;o)ydlB*lI%TJhR3--jWLzUa>Ey8 z!OJj}cQBBh-rp-1dkd$WDE|N72}DC>FP$*urXug-;(iHN$BA9_dDBy}ju;&siLJEp zNge#Nt*aXIl(4gF<;y>()qXyLFfm8th*rdU)b)Nwt>zQG*}!MEiX=a>fvk;&su=pxBYJx?a@8-zuh!fVK8}P28ni z9FAmhT^5X@qC3WkCPUKvsIcBwq}PUI*9eDd<+mohr6jJH*Y8DK_XtTnomNlY1Z&<` zxmg5R+VZ?YBzC8Jmf~Zh$$vFIw2emgU{N1hm6*ZK9nauFSLAZJ{X0xj=`rAz*xv_Q zcF~N3zg>OV{l3t?!L*V|)cgp8j#}8;x;|!5hJJMxQ3F(E6zNMmhD&<}k&Fk!G za>P4tYWo7MSVE`cF~>OTy|SkSZy&%Kd$QY3Sala%HD(9acCS3Jv6P%4GVrn(Y+aHa zh#$U)H4Y=|d(BYz0z>$V7Hg3-!% z@ljHYJq8~4s^(5r+_j#l^@JHNP290BAL{9Q!(qnj@~$!Lt+G71oD8Oh^%=E|%GShS z%eb}%%O3BEpRmMV#H;HQZ_w&0y#0BMyqJ6c>H5=l*iRvYd-NjC_1qz1%oW{V;*YU& z$}L*dj&HwfY%@u2SB)>c>yD#*yS@A(zxf!KA<#)I=UpfqYwf#2y}oLR1LWQl)Cyh{ zL3^K*ung_Aqx7gpyuy&|_Ent5g{cGu+p)51blk0+k z7KgF-z^{f7>0RIXN*r13vjzJ9HUy8IJl-d#RrwuMOa zgnl>I-#B&l6G;1=*nHkyesbr7zOxkjnk#GAq_;83xB_dLs}@Y->ci`j<;72Xffy6$ z%SVRLQ|yPggNcw^da2*Z)s!sL?f8Nip zWA*vOs&q4m`M?y3GwN|ZsG3)8TTOZ(AnORkwu9}N{|H3YgdL1@u8SCcm~VzlirUUdoxMx z_pKAW@1j26nt09rRqq=U_=Ghq@ZA@@J55#aW%>9@-`-9->q+KSvEY4jIK*2Hk;w}0 z3=(rj!=FX0YB>#jz`ow|`_#0GZC%o9=dVuu>i@=>`iR`U=x8K=nMXeB^k=$UxxQ@j zL33?$n6D9g3g#4NbJJrU_3!)1x{!aB$ooksR+iNNm7`pMg!g;D6%UUyGG?o1PGZ$h zyL0S?RgBMHWuXUoQS6^RiR70Wm%CBFhpCrsF|Tq1JRhMF5wnUP!a+Om-`LGllYHSY;x}w;#SVI3d(mhwNTzL2#*`U#-i?Z08@y1Mqq=(B|bzXe_lV#R3M`meaTw;G> zW8!dPrr(OGPOc#N;@FY>?qShwiH}pp+LP;t#KOe&={`<8mhRKUh;;iB1Ja#IJd|!t z;v-evhKY(sA8$)+_LOJHsUfZOXQj`RRUdyX5Ha3hTa#eGv+%N)$nYHdX-ifWU|d15 zza-6<@=46nzYjLVs-SyuyDV%xiT{7d?_SXFY1qSVx%6HY!ZB*&vbL0VW@j&9(O-#c zzo>#G=q?3H9f4Up)RuOqRawe-zZxk$$-`nqW+;E{;0ax@pV*Q0DOlUyC;hZKW@#_h z@|X`el7-J<0aLv@OdrM@tL{pZZCU3S67I`-8q#tva-X5S^JrxezwA#ZEg->Y;{(fB z@KjH0B+{j*<88%uw}>%6%QPQwURMb-63T0519)D}J@T=c7)2dT7ca58muR-W7&iCTi-R-eEwNMMmuA16PaOq8K5?(zdb*0&OcQ5f?pb~I z+l80Jd9%$(yE3;FIIMvc#q*BOdIn$~tRYls7Br_Xx>BUBi z(qlGAQdDkPPBf|wHyhwCw_4{GJ34Naxf~M#-qy!a{%RpZC@bEUA%nZM_>thP}qwz|H(?4tHZ_NnZcI z1~Ps{d*kGtrL9-~L4S@X=WFxqWu*Qn{-Yh*RA%FZoTLtjH8 zDcbvYvKqcs#~jYQyFcCmG;bCS0h$Gy$EgFBq_m0OFdcw$`{b{)^mB(wfiOKwa(>$BgIg|#7v zD%dSPztebl7a8~*HXJ7tJjWwPu;eM`cMKzuS>!REz4yhUo>ik50DGFT#KBN_hR;UI z-^SyhFYtgFu3NwYUgx0`c*&A9Rx!c1;*--X_CC?)7PC>0i_Nja*-mo&1}lj(jO|IJ zjuz;)jIYhb>Lx??MI!YPSpPXIj#Ke|;Bm(>o&}!Y(H)<{(wejE>FyBcUv0y1X2_N% zV`%TDG1c?DWIz9n*$2DyF7}C{kn=tplJ+(?C>zW&vA|F-V+V%n!U zUHPbN{|UKwOKj+-l>78)7TlSX{J`qrzmo-hE6$Xds>ie4Z8#Kas0x~m4!=&`L^s#b z*`M_EpVi0zBzGsP%l7Bsl^6A=x-6j~-?|kt#+eBj;qg^f+CSazW5}=y8pK&F%eC=i zsBl;hW47IMa_*7*ZakhkgVznBw{G8{uRi)vU`Q@3F=-$LnMpmvtTfRv(%(Z&-N+Sh2SJo0UG*1t$8CpJHl*q-ue z;$%vB<8DRm(^|ofRUJg}F2>uddp~nx8h+LZ19%o2c}6UI7LOTaPVE>>q`zEqn0JEH z6clx1r}x4T?k>9o#J;sZ>scOg^-;)|MeDNRQ?Vz&X1xv_PNSDsyk`0T6q-#dtf&xzvGvBx(&b(KtdBvumhw;vN19%3_D z*z4`SbA#7eE4qG^m1e^mAC(Q4PaCN5N^lS3EBAWjwciIOtEzSmN;*X@y~LSn^aP6@z>v;nkg|`9jFj(9b$v;!OCCF*&Bv| z-D1S9MWTQeO!p^#b!E(Bxu2b%B8&gC(cf9sU;6)}f46$SHg9Z7^G(P*W-#yJg`az8 zBTY}moQAQR=JZ+9&!;z!?shA_e(~O39DfUmA9ly3+B=BlL~rNG&eqEbX2`n+`8?)kZ=}N&Y;B4j z_VxL&w03mH&0EuHD;C;{t#)zkOKfxoowt+6*I)(h+28Y|&>6pd+>^5T>mGNAb?>oH zcdSo|Q@ShoH1=+c6%!A-Thv-_O!J|_m`Lo&a7jKMXp`RevZ)MY$Iz>KRaa|@dk@0R zp3{$3v|7Pki}<7n@2uf|u^Ocwxitz4>08~{}S$Xi&*g^?(z+9 z_`x2pKc+5)yYFc0>z>s{bv<_bkIK?s*t3Tmz96rd<^DS^aY{u04PQy`S>KBo?}?`i zaI*g5W&-<6TPC93Zi ztzuTiMg2ZT4pB23h4aUVUhFsXH@($k5zmROHN}p+GPgpiUk{V@(`5a+mEtRTWvtc9 zs)iUl+?B(VGUFzBFwyKdXFqEmW4y*SpL0m=5Jg+szUkr zPiYm`$7ta`+K4kg3S)j*@RDCi=?iS=Gun(Z5+ZIMOw-dAnp(~;remW6y*Gl~hr_F- zem^K)d{6er_4X*6xkMKk*kdj&&V~8J3A3Nj%2sUj7+G9{J(cj;BP#TTjaok>dKA`@ zTsY<<@UJH%ogiwrBZq=;paev{pC!i}{X590JX|cty0gkT{}GK2knjgQVsje5vX>l& z*G~Jo;v1v!xfxjA9CeV_NpGUR`{`9bZSSP7k7;i)7TnzD&qDL*xaexv&EU@+_}f6= zecn5bcx9|7j(tl8<1Df6EOu9!<$E8w*CCd<87eJjyOY$4SKJOJI zk+OW^G125?rw#GUj;yB;eP)+i-0q1P%tJ|!7iHCh%6zq{ zmNeAr{~JNcXGElcDn=)fe6~5OuX$|}Yxax5E6w?P*_zK8_6{3|v$lkZd0}^)yjzXN z%aKD7zr}w4kFbF_CH_Y8iunv{^zIccj}xmVvcrXGXmb~~eKomSZnj7sF~fNLVkou> z0!$=>etz#~T=G@Sei0vCNB;+4!$EfOseI~xEc<5K_`fPrIa(=%g~hJyOGWijo*gTI zqi<#9voYHAp!}npw#9yn&%)4-Eb}?-9PINrAN6S?am9F9Zu%~P4adF!+1=w7)x%g7 z)tQF7d0qqlkeeJ6?EiXvEGzHK%TDgo^Ej3MybR|kCi<8CfbaD546NYaw3*Wn;tqxV z{)hN!eDNqx$LYpn;29XhnYv)dp+R?znxbvIb}?5ukX&mYXb#UW#u=OCD+|Is7LYA^*b(%da<=tah$rAa*R!=-by0M4c0Bu^yM)#Y~_*cpc z)+-M&)a=iO6=DB6;AR# z_PrHTIqI9ISoSIRJL}1_wDckG-3tdE!Eher1F=(h@Ysxg{tW;AhT=EVUwT(=p{oX> zbygNuQ10CY3Xg}4wQ2P}F{6l#`%W7Bl77B1Po{{^=Cc0udK72d_mDeuVJ9s~q>+B) z#Y2u^H>;uT%XBnd#u%#)#`5*nUa>lC6gyZ6%ifX?ZiC%l;U-7n;79y?Gvrtyms!Kt zFN#vx#hHj9_o~MiQokZcS=n0Eg-_)9pW}0@OoqQN<5s=+ZOmru zt)EMI-q#in$H9ZeIYLQ4;nAp_c4bzzIqk0v4xMXyJB)jo!bUy3e4!3se=^-*bIT2ROppEjzazix534)rK{-{T z@~U&O%Uy5(AE?bkv6k3DbcOFM)Xo<%8v7I_`{HEH*i9XEk>_#j1-$wTSan&vxrQeG z#TTz=eXzm*v?0z_Jto$@fw}hcl$!3@nf0Zn?o^L0tL9P6yyHxA#?^c)FD(3B^tvcs z#vV{Vq>X=lr}p)$QGj#m-~Xnr5FeMxUxw23Gk$i3*3XDYHTgj$C|H`j(u;xH$#RLh z&{}vD_2v0#J)aGGX41w4xH{Qu23bV?VV6ksg;xGdE9uzs1FS0#hLl@d^25n;bn&EE z-wH~$q>W-?Ofh!$s2CCZ=RXYjTgYHy-~GmNu@Z8uJbGB1cT`Oq8JVeNv7b?CoFKcN zmSCer#ngM<;}-AV|73VbF>GvCCHYZucYFYhE^4Y*ME|X2nl8-&` z{^5Js*n45|E30U91^YVU|8KI`msmlZ(7H@TYYuChjv>D2E;C4GCH;O#4l$Zs1}pm` z*;DPdiJbx~iPg2t)_WQUscjb1lj^)rv*Ct*Z{+hL_U6CY-1d@cx`U0e4`SmZ{591) zu!(#pHuHDt( zMkV)s#y4Jv1Ap`N2Vn74mK8H?YO|!;EI4X}(_l#^zS5l*Vpoi9Mi&=hG%-e!73O|L z8uRtjZY(mQkJOGAnv*qGt$DUu^#{o^Y`PS#SxTL;nW#0z)$7>DDz-nIr^gONbNJ|d zaczY5jpya>L(mJ_d=bn2RbTGnqXo3G2+ODsAICxQX=!zp>gonN++(=hW`uErNuIKi zZ^RyL?};oIFuIJ1z4lo9R9#@JIR!6@3vu>!F%}YMa=$6=y`c@Oe6v4|6{pk3v}Pb1 zU&6cR%e#j2_(5J>Ay0d4e1?=lcD3mtQ204_sZSFzl2L#q1BbdpiOzJ@PGznqKH8XmpO8a7;qS)AMe4$<#*m;X%c={*nrmMZPw(wsQ{loi zpAB)pRlc#9?7C}vKi?bT{_TCY5?hGY7n5OYEo+)Fh=uZ9Iz12Ito1w;EndJQa^Z~9lYw_INmoD3!EWx ze=f$J#-EPjM+a%()ig$QSzKC7UX!(EmHw=k|7$oICZM*qR0pRnR$iYnI# zb-HQRmJBvF-bPKkULu+D0M>eimu5eQSqNKG1}EN68EMT?6LrK=KF{grMG`ws zhnx9QA5V|n*E(T0WuRRaSxG)}%fc#t;f04}u)A=>IQb~nZoB~PI>Wj$`g|vw$SZz7 ziETVeS~tRiACndBcU99kRa5cpIo7*@^&ez||6)QH(q`@*mV+!3>Bq8#rlj^H&eD{v zR)G#hcvb8{9rM`pv%yy|koU3IXVvDe!>MCuv~j$qgZfQVy841-tJ8ZgSN6q2m$0N* zLEDJ0Ka7E7hUzg(X0MpFMvZrtoOp}&p1?9zzv={Q*aja(*DIRfMRFD5QKjn=2YI?ixWyk*Sw+mJ(U%Y^4oJz^9CS92=c90`< zQkyPn&GI#B$a~D3_)<0JcO3p(Nbn&%c*}Ek)6BPId4FOOTYU=uF0HTGAbC!6K(9-g zj}s0^tM0tXC*LK_Z8Y;Op8A&+;^$>}OCfSwc9p}PAh)FMv`#l8{B6o3CqTBHMl9}N z$93Gdi~gsRTjpU=os7N~u*Yw2dl-M7e3ad8g_PgH%~x@*!N%Zfr@m^8wTiLlf37Y} zUbs3ad85(Ohs`qXs^;ZXDS6dmUjGB+hzd`vFvx{hg=NLw_uC-FcdYz^PjZWyWwEQ= z*vBojSQKL^E_&s~@QcVs^5D? z;fl*fxl+k+DWAxyE-*$kIBh(t^Nvk1F*NVRDz?;Z$TF4Sd zW0?!|Ja(HIB%hc{22)u~GgerI%~WQmP5FNtyrY}UXbe9ehz&j|3RP0$ZpdRwL9EQA zdo9n6d5`z8@>|(_R=%8v*IdSkmg(6beR)P~d=@5+@EQWghGDU5#PF}Yc9P3PHc?$X zzTSBH*Jh8LVPy{(32z3^idg6Hg}DU_ovikHa;>rTW5zx262)J1&+k<_zain{ILHN9 z_X&GgNG^jsrxk6sz=OI#xTa~d+y{{VLbm>)>f2{zby94-ice+2WPdi2cur1rt3EzV zV%_lH(WEjG0xjn6Z^^m`@SU>oyE1>TLtb%;WEGLP0eQAJno)~vA0qGk5FzaF3M}6T zE9b(U$P@QM^r$VJ!MQfeXtvR+b9iA`oVxJ=yBms|%@q}6-QHT?eOt}oP2YG)Psg&Q zkKHMD^18}~{)Oh(*?IF4X&zuj+xYOC?(=^qIeY?hx0Cco>}MwyGzVh|tC|Vr$9iWf z{VZlh^Vr+V@|j7jzY{t2am^wKA3HSeQ5E*JXE`tWIZ%YH%+4MntFX(wBK3oOxdf!m?VBaBpcbsI zKI_Ux2iL)pJ4ydWws!+Ny;Jp z7d=Vz9w>^BgM=&8zW2y@7GUX*ri`G0X831K7TJjm)`}3>WJ49{|4$w@)aSWdMinD3^vbxgbbq$%u4%U_MusBz8G&xMCg}yAiKe=@$iLO3v?W$nr zne{uf>?@sbo`+rcxL=%KP#i0{q=In-kNTOX{iIFb$l^|jwLe42^yDA4lUd|H!0#1c zMtOeG#y7jtcbu_Nmn~HD)Ec~|8;;Oje0myRh}{ai(`G-hsS7PX;hk#QSA*6|xb{IF zRuE6Bp#7CZn0wg7f7+5x|58=BBiAf1?o`8~V`Te#wsb+&Af0dgKt>0|?HC!z;9HM) zw+#)qargF~I7~}oZD~WV0iGQDLG6cj7gW!F#nNI7^OARt;y?SfXBjy>!D3@ijt4z6 zPU^afGyjX#y{d*;lHFYvG4rzWQ6l`0Dq2_ZI$dv=yQoo?@05b*tfDR3AT6d>G;SDF>DyFF#{6qP+R*DD}9|sPbU3w zt{Uvx2{3sv{CSBT&+vN>Xxx;P`eOi_joF^`@2Km?i%XYqxfj`CD|SAR*YAU(h4}7d zQSXwd_psH*`J6J9$JwlRC63@EZ(BDJ=PESP!s$4bSKpM4<4T9 zb=TN;B=*Yr8&2M3wp^S=U(`s_LwI3iT=&4F>t#v@;PI!tE)_PHR*@>EVpD+K<%bgC zR|PzwBMq%1iOp2%=bD#Jh8e(!pW&DbSkX)# zHip$UXZ_BhV`)8Tpq`$U7w=2>`$0WBW$bP&`E?ez7eTu(Wh4hhr!Pg)Dq5*hj+zEjI*?UD15DgVcmrx+=4HpCOaG7c~b4*eo>+j-d4a| zy&TrRWi^(YL#-u|`bzSK)U{&5F+YDYmV1+L)>VOdR%X^7XMRfcsHRBqm?}YY9`};U z(L%9(ftayX43D+MvCeWUIemf6elE|7eGtFLi8A4JS!J$|!R1zvtT#*Vp|#c3kW+D( zFa6u-d!yA|hq}`&vE((3XOqgsHD-T}6l?d9<4Yu(VAb7JF^(E{o`t`zHOBl;va;R{ z*OCue{57tQ{Z6;g^lWi!sw!C@e7%hIcDJQ&ai+#wc>23$$?Z%YFq1OQZcVkm?r!7V z8A;|IW8US}*s7RAS<1cZ`CcX1Qp)(q!{(hnphEH(89t@vQq8+r)ZH?PuUE{=ye@S| zGJooS$vC;IoZ3x3ce%lL{!Bhj8!>mZiFbO!s==@-_QPF{ot(m3V!w;ne{BO_+A{R3Qctt;2F)7R*8MH&+tgB?y2L!T3yi{Pd?RRIgjYIAz#)#MZUQP@n_yJk=#0X4M_VvGpoCg1-JBhFOum-O2NTv znCTWLqm^PM-PvKRXMIrx_DyycXSjZY-`&Yap5UD~q{P`?Md-e)7A*4ZgmHv|qHOGZ zaTE^B*4779Q}>vSI7F^j+pOWDq*jZ4Og7K7PYaFusG@f4IuvGuqrbY zy^=ZvBbtV_%)@y$@Z7g})dulmEFZ3fc_y{!6Izaw4Tizdm+{B7_}}`ppEICj8@h`1 zr{#Ff!z{8$>Q{2hcaqu7S1pseKH1bBrZs525zic9%xgM7dYNs!#z)q$nuY$o!M+cx z<@^TGF2jPz&g((*-r6`wbncA{4}+{PY1fM|GWHBwBEJ6*YJQzkL9`#7_%E%-@H0f+ zkyb-^1=h}S#TLW{;lYHX>x2y!zydp$4 z$+?&N{R5o*g8wJkMHY6H2b!ed<{8<;eQN&sRQ2n54dLIfkmwH2jvbx;;t!F<#OaMk zMStt#jgqugMRCe_^Gzfzhe{x-ID$lpuZ z=UjHSL>BiPo|RcE_h1+M_-u+=VS6m~k{WCUXAb6YF78oWAac(VB=|iRxD&>m!r&g@ z4Y8)U4@NK_JJ^R+rQ$=mRMfJXrJOZUCGlXQzL|?T)!#Fh9<7T%VbHa2Hc3F|k9>lU@h4l|+j>P_tcH!f(W7*_yA3@AdwQ6{;~Ks{%Ph?XE6V=u9$Q(mZS;Ij`bj zvBvvt{TV0c!{;=-UcT@)G`T3Bx<_BKX=izDukLQ0{Oixk2m5;}E$(vv3*>j1od3jZkIS33 zW4#^lw%CU)&b~-xL%$lst*T#p=;=4tZ*LqT20d0-T0{li*0)hYHRd>jv zVrFbc8o8u$@{?L?oK6xuVHF^wtnBPsC=t8eoDyaCs>`xE9vS=v);OQH z0xW(CCinLA8lG1L61BwHdSO7Fv|}=y`q)U&I`8(voI66R=~_9T#ukYM!(Ceo(|Oou zPvWzEAm0R6&BIT|U_9O3v%gB$1d{3RNh8F7K>xXTM_->;6Bmk-SqW8_r?hB}Rvy;Q zjc|0K_J5-Cau8db17Taq66hLslKBhcRAM4Kod7H{s2l4x< zbUU3z*7cOKFgKq_5w-6aRf#>xANH!rD!TII&Z-Cf=%%}QnXO@URr5QFLB;}dh4fnS zi|SFZfrGTMA6iDm{DjsG5v3)_|LiuEq%V9rteD$b5t z%a>P*Z%ge2@m5OB#8)YK6UWp(zA%f+>hwhTe(cH^=aViHHC98ec~Gje?6f?;eFPr% zR$VgNJMnAEcqbH>NL+RG91^>qrNqc^3R%|^%LZ!uI@o(y{5zq|??Bb@deIT*Ya=Q& zk^kiq2jZ;kgDm?i_Pm1+#_GG{YK|BD%cQPRM0|J}t_*+_^ZkFhR(%9-59!g5V&Km* z?i7(Ss~)Eqar)kSzl#QcL&LAd+T&z*NGv!2%?^nk2Std_A@&Z)wE-S&#iovn^#@4i z3%I%iHf_?+4}AW%mM(ybi^S8VV&n6E_Qa$niX*FWuQ(-RIwXJ9Z&S7A8M5v~Is<*9 zgF8P56^Co{3*_0)&khi>sZV1)K%6O+31;19zDZ=aQL|2m_x#F^l58aA9RJ0V;tbhS z7M)eD;c3-FaDO z3arcM)9XaYT<#IP>?&m12a|V0pr6%vYmnwzUUNM^OQxJ8-zivn0kVHfkE*IV6p+2$ zuUb${9@JJ`h*K(OvF?v(Hvu^_FTKTq=UXOYM#**H~CIh=pQ>6Rv`N_ z@{dAf@woq2Op68SJS$EL``qgy9bLo2bHuo-m~a;l{zogW_58bV_9LR(BKiLS?7s49WJ>b7&1NrQO^4S#Y8~#y; z`c1}uIBkvY3i*7T`MO!<1-wM^R60WP4B0^ebUJC zv9uaMCi*{@yxys`H>VynE9!eA%Xg_uV^m!DYZ8J74Bp8a)d zL+JPf>&z?m{*%T7E@DZUSWm2YFT~w^6 znRgLIcZg51I$!~oGG2raPO)5^TJEo9u08CkSg(=`tr`l@O%b4935%&Xe_G5B6#V1Z;*Wbx2 zgBiy;Uq{&Ada-&q4%(Phy0h24sax^o)`>S$UQc}OY>?e}am;smL@p4~dM#$Pki~yx z9f7m`j6!`5J?=?VlP5Z9H!&}zbmB!Zc7)j!uR!GqaHWw9EFVVoCuR}(;@jFijiiHd zHqrV9s%*_!%wzg{tNz}qwwu$M+y{6|Q__Bc_rz%#GuhBQ8jTrfF&}3hPC1K4=ldjT zkuS2DINM_#KU%^vRQ)B;2T4IUfe8{IIZMQ zS*9;MyGtpw#cR~lxKCs( zd8hBoH<8ICbM-&}k$Wzz!#wnVjcx<5sfJZC1K}|k*vJa_WkdFpO3?Lxfb@9?W9l97 zwuU^>*Wr#kL4RBiI6fUPw_#82iGa_o0jDFO9UJuVh77kcVEJJH|M&_VqY}y!4l;K* z*d-Q&yv_o@$5xn2(NKRSM94%z>kNYt*|7Iy4tOUv0LQrpI&?8`B0b#c3f#9LmZKv` zwjLlcl7Z1QLn z;WprVi@`cE3T!ZQfiLcYdA0&DZz|y39MGmWz~de;+G?n^78pq-c&n-yYGy4&cQ&l0 zeG09z3fRPEXq!{O&elMSH0-;&4Vc9=;0*m>EY1LKG6`f}BGlXimZb(u^IX8-c$hKS zfFb<=Px=8G&IWYd3S(^{$c}k{jGLezH$V*fVM~nb~OlC;CdLbr@?mc z92l<|7*-wZ$oc@dX#te8p`?}IZL0zFAffdtz@l*$lA8h27TeoG+?L=F)yjmgHNH~W`I7_;IHSw7`6EaL%xQkAR#ZqTyR0@a)BZB zh1yR57JD8_@)cNd!##{}e=C%u7}(!W7<*qqXLtr{i$8*{fI*xf3+znQuonIX#C81( z_O0V^?P1U$_5gpL3l@=FC`lvWYq?OWrqF)5FpAnk&&0xr^Z#GZHpBe+1~cOp$dkt~ z=I;U?+=g-g6CQft_Vs|iRq&h#?c0zO`ZQd-54hbqkSLen-6g=L3cw&AjGFK8`vydR z4cM{|uzmnAgeEZ4Gr^|N;DJy8&td>tfGY@cX zCg9n4kQXE1n$aMm<^e1F2N>I0`0rUziiTZW8dgyVA7D>|&!=IRrPd&?CP3Nu!CjvN8hwTmRf8;20W)ma zfiVJPRYR^{4y;6K$coya4L9tJ(-jb?Ghp2)_+2aT^O+$M={VqYKPY81_$OqLrNK%s z@?W8w_@~i!x*P4Fm(Y#<4tk@13gm1!48DvR{;z(Lp6K6BNBcX`QU0EEH~(dNEBH>T zp{5xi2O6v)7oe}6!JYG=--@B#-a+5Ig#IlD3GfB5^D5{kM`7md087hZ;HJ+3CyPOw zX|NQdFz?i0Va$MWnFWZ{z+n(zlrBJX3;22rP_J6}Cky;<0}I&?HCqqd?hwek<6xJ$ z4gK;O#>f@8=V@r4vrzwk;qEt}EN?(^z5%4qhr8FoZy8{JlLGT>unMKZ+-%sHuQ^~8 z7hatZVfY)$_Y6j3!>+jvF-j}p{cbpO56;|&v3CgmVJG1CDfq{R9R_!S4|ER5n;9T; z*FZmQg>khOj;$agE<&HZfnR)qN5jsuHPB}b`PanY5%mKGqQHI|tYUoVJvJ~r1+d~~ zQ1AZG7F_|;+JT+4VL$OU@MzdOmj>Qt0E>+lX1EF3upw4Y3m8pcL@O|-;l4qAvZ&VeexI}YC|@HzX1ae!t*V_#uqT7 z>j4*7%xi!-4H0+?0LdHnTxbgD6AQ210nZxtMOp?JvIl(HXF*;+1mrje$fRM61S^sk z_=pTf-6ZI(0+>a?pm{a}=HIa6S}Dx0_3&LdFu2!{E94FM-)!KerTi>7w+i~R5c=B( zcI6gOrsaT{X93f z4?vEugM0K0obk5_Z1?vL><12c)87v4kTXFtuLs#Y`~T;sgMV)?Tx0bY!C09C?OqAB zPGs(YRyYs#m63pPEEu0OV3Z#Et`O{~;b2ug4((+GZqg9-x}CX*i6UE>Ly=3&qsUX{ zdE_c{3UZAZgIr*KV{Qfgc@@Oi%w|r6_?ngwC;JDp4s!ZG2Aj!C$cz32e0TT22GbBT zP!2ZMGDa$V-w%9Svq0D02WD%wKRn2C|olAm^EK$RXAVdBYrm z=$PXX4|6ucMy4YoWF|s0S0GGe1)@TxB1&WcB0+{DTx1NKYme}d<_OLlj(lUzLEbV4 zBJY{$NFg&4`Nd3z++@j+rz``>XZ``-MIz6cH4ydj6TBg1%>B$S5LsRZQ9?SXR~5v8 z=-^upqGxgu22#RwK~zW4|06nnFyBI)$787bCCE2%1oj4bDfX2ZMA zh>=;!JPDCUvmig(YUVrUGiDv+L@Q_RWnO14VEzL!Ca0P6m<}c%X^NadHXt6vinK*r zpd-=wXnS-o+5}yWHbRG@k!VX)f<~cwBouv#xRA%lYvesrj#ME`)PS&19U@0jGzP9{ zjK;#X9nd6nG@5~SK?lKq3`cvx>tEzMD23?O1L64)m;JAn$MbDu(;8B3SLItefXkS(`t1D{`JfC2-W&L8c zX8mTVSPxh+tmmvY@Hw2dm!(I)pr24adJnyYtVQo4ozU56Gt|LKKv%MBkY223hzfm# z>_m3K2pol6W_Cn|Fq5FznQ7BY(|LLNeNkRJNo2ct=ZR5L@6ugqY?0VBo7 zR3jEBxHh9o0GgoR+t1mrcd2h6Vo_y?N#27dDl=D{;&d*nLIyPZrD zc7o4?=<};EXZFD^SYps8asWl{LHykNxGJO!t$}UV7u&^_Lj?Dn| zK7oX~3KF&m?Bq_!$eIp#w-)B;9k4AH0zQ~w^^gU)oE@|{7sSJVgzruP2VW1^*b|s@ z8ZhfDKz9^m-f`eBxge1}fOfzBpS^4yc>hNM7ia{z-h;trkl;`ANBVn%WM1zN_3!qF zK@^9=pXgWl)gXnN`oGZa{6Fbfzu2GcZwB0dZU8uj{{Wxk6HJj>0ZKqPG4OCZZBs_PZwo!ek@o;qyY8Ew^noO;S zYoAcds61*1b%we{t)_0kb^GDEYjDLUxaJr&n(9w=rXlM5V?Z1lDEh(%0{ZFZ)6&EoXnw4lPT19 zvM-eZbv;j^bTZwM-brWDmuMcnkCxHPXe-s0UQg9gxzuJViqcSe@)UWE{D*u`>d822 zCAFBk0Ci2Hno^VD9yf?KWDg>e>_wpDNFoi6HRN{UCV7`AB`*^c`HuKS{w8jdr{EY* ztS9>unPeLRClrK^D8sqrSG*0`n3zajCH9g^@-4ZZbdxn?b1Iw~K~0BNehkNVcwa$H zp-8y5jGj(m(4H@;Y1CaP&26}91N6v5c#MXgOQOWoXVOewC7Dzq)RjT?rCj7HYArdI zDj?pGBBD9D9><9}xPmOe_mFFdNU8<7hx(TcqP64*I+GekXH#=&8@Y&nOtzu-k{C6E zyhaTs*HI(LrPO+IF7<(2MscC%TT@G*_YXo@UQ&(dkJNhFK|P`4X(Qd07W{X^(w{v>*|UrC4gh4fRnwiW%Ix=LN7VqnZ2CihW&$+c7(*_~pOO(}}# zLDdm|QvVRWsRUve<;N#diNrkWAaRf~69rTf8Ae|uC)53@e`$oSpsQ#NuDZsswJ_J+J;Y}3Vlgbmal^R z;k`(1^)4Va-m&C!PiOMA$4AtAtVEQz6*iiGF2QM% z#>Y^Li4D{%Vh!~O>UNjNpiU4qDD(L@o+AP5r2Gbt7^mTE^Fr3MjR zDwpU+_a)}i^NHj1I--caOql7%1jm1oXyboItnpV9SNt*LXa7f%6L>tRp2X`gfwFQK!!5=qU)G<(dW!KmW^4!Vjy$a0j8BLL^gA} zB9YwP$ad~q1mQ8!iM&SWCSDqPlGhY{$Qyv3@>-w?yh!vJSA+KAdJ&3q1G&pt ziL~I%My|2{L@T8Y?2lp-dxPW;4pX|2GgrEa zQzzZRiI8pONMt)WwbG58HPU{ZB8i2Ki>I@zMa8T+!e*>m{#LXjuMXM8X@Zoo7Ba)p zr;Oc9CwNLCfIH6gx1e9sFGva9npi;H^y$dH-sxnFM@>#}pCPKSNFo)h!>_sCGIm9Sz zC{gR`L5y@|6MiS3`06ac-#ee-Tb&j>(rL!OIZop99RJ`J`)Rz$z6EDGX5onA7#`;+ z#E&^lcuQvvK|8k*b*@i@73)k+_QX=1e7SUIVxYe*)iqE+6JRHW{X4w=k;dQ@l)88Admf0n8wKw_2CQ?_2mo|_2+aH4dck*^A}-L&NX2W=c|y% zQHy$T#)}?tD3P60D^BB@CI50IGMvkjPvCu(qx_$W)%-H0k$+t^P_RI~Qy|s65nR=f zg3Uo(VSI3uut#twVVB@`!i3;dVMUNgI6g=#IHf5R*wn`av(=y5uERWYk zZsr}4hx2vvru^=TaQ-=kkndF_@VhC~`Ky(D{sN_z*F<@lSFh;78=@%Zj+A%hCdm$R zK1g_+6!9c>AK@xiKmJj)2lpeA&Msm)kgH(FIvE%QQF<1#kp2g+r-Hl&@;#;{PC8SF zo%WshTk9)dt|i>}*!0@F!}zE7iNWpR7%DwS^=CaZ^#eVKzNKfQF3~el=XWpEeRFTt z<-1?&n4Xbvo@W^0S#LP);Tvt9lg4PT+%&{H-n7Ph-E_puHb3$XH-GZ(Fc*1WnSXnu zEe`KmONOu3vfnqv%D~@S7vqC%PCV4!gLr4ZN{n+PldYWl$YCxqwG%r-J#{yui#_GE z$GhJjk0%D^5hnvavOVKpTF7h^r~~`cIiw@f9|e}l8pf_|9Qu&TQT%{H)Rj(C%(o_q=g69ZV zgtQh_g(}1Y!%M`a5gR1YQK8bD=*`mfnCH?PF%{DM7=~40XoG4KxXQ}uK_pqc9Z>BVjS1Uz%Nir*U zg6sqLwCp7JmFzrsm+TR@o$Oz3t#l5zm9!goz69eO70>7N5Y@3a3sTvqdCgecIB{q* z77cnx8RM+~abO!c*}o9dZf$VCChs}762bO%c!?#__r}!M``WO_6R&^cep27qJwf{u zn_f2!J6#)!mDk9y1vR8=L5>Fk3;F}4@G1H&EV$)Ec-ZaAJGOhE4ne%+J z%{*Ld&cWwf2IJAzO?aNwgpaiiBqHrch-!N!vEI>|{L6WbeCirNb#W)sFR94LSV$8s<92Ptfz$A$!qG^atxAs^%zJ>$v%>9R4YGK+v1>K;+__l-%LIm2Kf^ z71Q{iRc!_RG+x2%pryio!B2$3khj9+Ayc#w4s#+eQSirk4kLE3wz2Qbe``;9cxno4@IVnOrTPc{x4(7XA$-MonWn2X- zmwO6TbGM;x&NZ|>Hy^F%+RzQW)~s>-|5!T(O!f`o2*CfxY>$}9xh?6>X)pbcW0pSR zM9ZFY^5FdnX&8qq-NYuujo6n(hgm&^CFpH_IGWGRMGmk#F`J{gU~yFjV*GVtZ_cX9OS)Zka^DQ(%c`kyRo))T32vwmaC$=$a$ygw3Ab{#Cf)I zgmY?T8|Q+`cFxXXSbf?Ij1Mxv-FXkPWmpMA^Optjrt{?BK;B1 za6^HooiWVY+O*Z1Zf@(FV^QEPYY9Haew$!Bcaf3UOlpniFg*fy`PWc#M!x_H)>SZ& z+b9#g#jZlvbGNdX{A~7EfsOrLc$PCzJd*2?uy~tg3wfXAHl9Mcg1=f-!7o!c7f6Dh z3Yfuv2;T?)D|{Sc6ut`0799v%B>E%#q3CHiCZfZG#Nr6Gm>aDF)r3;QzeCG~?vRhd86g*i2ZNUgj|R0AmS}zphH1749O{XJJ?g=N zPU;o{o?0Pzqw?@isvf~H9Pp(nze1VFKdpSp+oDYUx$>N6Asv zJ#iKKM6?yXDr|&i2(}|_d8e6m?9q%kwAkN-kweGQPe?Dmj4*jx;grkiCGEF8^_KbW za$|qYsO#-gY1=#d*0gh+s7$j9e><%6OG_=Kze>#;f4ny>{r1y1^NY){y3nkD_L-yq znLk!X=RK>x^dY?d%KM|*`|r}UwQsN0b$#2XuH;Rdx?^uz)@^+gTDSjAM%{}ylj^u{ zr_|-X?O)gN?WnpjZ+Fz4eOp>5eAh;M{av1R`TNoJ86WP}mwm9;AI|Hn%l>#l_xxjw zetZ5c{q|2?40k>|4B3SbjCDl^P4~WDG}nIrZ0Yq&XU#8>+qadsb!UY%vV@234EKEU;mkb5xlhOa$6ncNCG;;le5_>P*Qe={T5QOFC<55&qn zjRtswSiu4nGh3vqNHzIw@8}eipIA`64v5xeyOpC2*-r_@Sx@{#eBb-Ur!n?hvVo zV-t_zoE8>V>V!re3y6O0r8sn2f)EHFohhfX7dHRI>w>tI5NxG?d z!8&FhLudJrqwAHoM92A9s#E1J(;xcO+%Uf&-S~IWP}AP89nJrKcbnJ#G+5>qyR7|6 z@7b`jnf9f>GaaUi5=TbWX6KIT&aURQI#*5I5o~h(DEBj+(QVQX_hc9ip6jN|-oGrD ze5-9Q@C}Z8gu*qOoP?E;T6Yq)(Yu2hiua=TlgGd!kOXV)_cFC$1v|>w$ZE=e#hxH^ zbEb$Tyc1FjuT);lk5PRRJky*I_6%7qnjf}Wd@N$EL>sk8%8uf1us88aj;TJ`c&=bOsL7N1Z)tmXVfUC`yf8~0mLhfzJXwEkA5B5gU zF7`d)c=i|}!I~&M#Og0R$Z9LR&srw@k5wmJ&q^1qVErMQ$!afZ$Lb{tVKo)$&|AW7 z=siIaI*)%HQS)%-2~I1fjQx-?4s8my*Qt>6e7Zk}8cXlN+fr9OT=Jl+0H14L>1%I^ z^yV1r-KTX{Y_~Q6E2^F4>Q?i{>8NVqJXv|!vAQDC!L4xFn^ZJ)oUPd5NUgLxE>;e5 zW>oEWDypwJ=hjp@(Yoob7us~}vF;~!!En(%(e%cXW;yTW+Q#_4+I!;boh=CoCL%Yx zb!4LVKkA&X3H=VgLw_K;`1K@6X8Nx{Pe0074%y|lLT20T%sb3{qyzFN>kjgT-3M*L z6|&CpF0jG{?bsWHrEH&Q8E2WKH#bEV!Anq7@Um1^ej5!_xHI^)@LOmn(cbWEajVEM zNl3I+Vv2bvy%{%KwlN`5{$~;*wYn8j*D^e$b&IaS z&2t6>p-ty#K4+~|?`=F!mDXsM@_6b1MND#{{CYyXEF&&Q`Z2n_Oq& zt5r_m5{l0pt2~+WO*V}^Ub=?$xA-r#l`sRj!>eXIWZw!LL+1I9L6FHHY6iq~7T#kH1wC0(qYOV3!7$|Sa~IY-Hb+@o6J=c9$-_NZyY;kWiymu3ZAkTW^6p!C{)3eMZ_U+Th50+8Gh?n$ydUAjZ`|Unv?LeCHc&wJfk!*)}F=v%* z4fmyD1@DP!CjX>npkQrqW8sWY5y)n@=vw3lac%TJ5>M4L^O43HZ(PBt~IUKENS{nQ`h97CcDWZ&8BQx zeJX3Qx=$ugU7fK`b-Pi%@>se=IWz4qMcdS$a$ZUc`NO2kvb~9MvSSJ7q&MT+O5erh zOFqXAkuYOv@zj`O;+@gW#E+wlqTW$QL=PgniYyTv(e#MBLPPkU!uaqK!GN$Kf|;Sk z{Qe;=`M-l^^0=CP+(^|94oA^}y+&$AD@BKpSV40p!Kn{iMK}A0FpOY@N+mV;dVGr8 z^W~)jd=|Y=Ysl84pD8e{YB*)>y`2y7H7#w^Xgx{On>~CX3YGy+tB(;k$!gJ zA9__mwJ!GaDP6lyb9CGCd+6HbH`0aYt8|Kdsjf|alo_*a z2ewwEV^s(W&=THdM8wT!eqnE7wqUJNdsXHKp6~kR?hV?DfZs|d zUNO(UwG6lREIw)J@}rHp!&klW@4_br&ga|uZy%rN+#hP|=f3Y)pZV^yw)fkW+RJYi zYx}*~ul?uEbuH_yOS|LkfcoL@uGNov-$r-*15@Aa<2!xwr}GAB!B!((ILh??%b(^2 z-@01De-M^4KMz%DH2`9_*?U%K@vZnNzr-aEFFd9Fp&HTNd^qW7}jjIRzvP;(fK{Fj-q<{Ehm zT3Z_X4(My|+4uQZID~Kyca~%o&njEUU#OfYz|?JoS;1kV>`+9Eh8K%ZMVykfiW&)e zxInfv_KNIjTr+u1{B=2!7^H|z>Z$0TyjpQOMXVI1WT^>!>Gase;z3bfp+9VsV1KZU zXI6FN=E`rg4dN8m2SFWjfm_b}%6iD?imZWXfI0rd^d9;+>7WX6@G1DJ$Y$O#4h@af~h~&sDGaaJ7EI`+w@OcjN0{z8hBm?%n$OSMQ$He|m@4uX{gM zr~jbT@BV1eul@AIu(RN>aahqB6ZU1adFD5P<<<9%mPS9rtdD->TSt^kwNa(<_Lb!< zM@GeMNBgRY&Ym^XTrKLRVt>}BxmW2i_bFqk=Ysi#caL?iZ?%0iKEaty@Gu`S%l(MF z=lPpr`Yem8cGkjZH(_Ht%QU0kbN!GEh7A*c&lE=&nKAX*aX7C(&{BV{M-lI0|C zlVhn<73~|PD3cl&Dd%SnR87n}stV2CrHak&tD2pKE1P7FR1VJ=qM*}4J7NS3bh3m4hi27%)3~h{SQ{50}_qs=prgZ}y33W8p!z2tl5`h88g&Cd73t4?-eJfqkQqw~w;Hb$(V$n3Ftz@A-}LKi zw7L7Y4QA?Fo!Rhxl7;vYZtd~whxJMEMw_B^qOFZL^ zh)-jEiNAL&CvUhD=wtXd@Ul!{3<57G%6@?!-Kn#RJLA$6il z;X@^dqLxeB$8MG_i=Qq3Be9F(eG;XJOc}5Ar#x0pN>!^?r6#L-rYcl-Q;f=A$p@6) zq!y57JWug7p}AsJ{9XByxE}Ihu~o9hF{fpNqu0xfQ3GTZQ3>!GC-X-2m356iAuEsO z$^VPlDE}E7p%@zfM!`s2uGA+DR0XB>RgX;{sM((}An0CZPVoC|ZSbz9b3+t4n$S7T ze}x`tu_5esOJCUK+???G+*#o(a;JsYx73GyY7re4-@Iq&jAkQ4#xz`6*H!f2rg+@2R*cuaTI^+aa=W^Myya z8euwjumIyc=Rf8==AYz532@F0!7A=*VLrEmsE&J9WaEa5!+7l^t9gVpm!GYeEikKo z3G;#y#4AH*NKzwiNN+@y$$rGt%kRbARxC@HplqI$s*xE)Po@CtseZlKT_#WuFt~%Ssb+WX^DqVQ<0Xia2K z;g#^dg1z8PCAueT@nx&XH-} z>BKTjfJZr_eJ$;Gy^pMIyu&TmJ*B1$&rsuLx6E)2^XY!Li2A0kCiO+m2ikqkgW9Fe zTJ1{bl=}TnZ~c4c99^*MnQpWzNx#K)LI2G4Q}2d@i?Iz1EYaX}u?;_6di_h6TmR8T z=__0|{dbpEf64V;f6}!SKDW@zu~0Y|`gn|^{}UUkACDF2w_+&HOqh|Uo+Qr|R^}_#()hN)Cy*zM~ zeK)}3Fd3sbeHjZmiy0F*+ZdUgU5s1oxeP0-2}8;%4A96(@TX$_fsFAGvws}C=T_<< z*@LRUmy>C}2gFv7hG4lzHX}Q;|<03dfQ>! zym8o4?;+O!XalF`U&l_*Y`fSax3zJ1u&l+}m|nYD8tyt-x-*XRb*JnpH3w}oD-T)k zl~1#zl{PV-_|?@E`=dK>^kxRSXpUZ3cuUv$^N)IWzNY@&$JN^1d5yH+KSXM`eTdS| z`tXPL`iDi@w7gx~ZFwiOSl&zR$d9!4{>K6J{qwKZ3qB#b-Jgc**q^WKCVgh;Z-4Hr zZ&h#<{xi&=FWhU`S!6R@ENW@YEs8K6FI;Ev6wvzV1#W%Yf)0kh1*gDHq%!6g95;3= z)EjRVYK?dy*OXo~%`~g%g{iPeYEJ($&wS)dt@*F7(=El{*w$M=?f|D)ZmTTmXb&%! zIHD^|j{M5o&Z*V&T%y|1*sZ!A?q&5{Pd9y`M`^s`m6<2{LaiKJV}F6?I2RM$u^7_j zE+EHwhfuG5=c#;LK`$fD(xXTt-IuDTZ&OzKUrI~=MctzlsAKdhawR>Nh@}VMm#N;q z=9I{LjXduTCMRO&h#*&6qR??0|6tF>t8FYi-sbXMv|4==tiOGWtoMAcz(3}*BKSyK z4xV7&k2iP36RVv^iEl0`ndaU}9`Ud#i+42@g&V1!LJnQ;LF^9$nzavph!K4raTede5H|Kcs+NQ8fKHR2|` z{Sq19DSgQACl3-NDdq?kDsBpnDlQ8aDGms@a2%4a7v##v3a-g=1fQfV!B0s6Um`im z?=GIpUnXkFeFu^_EP{9UXlHdZrYlT4VoBEwNjv<@OKMKKm<*vOA~?jtsi5^D@nH4fS)d5`VUPSYWY- z!{Ga_F+SnrnS01y$Vxg3-4&=oH#4`f)}m9`57^T=cJ6$r-(p^bXaawlBv-IU#ugSS zE(qo7?xKepiC7SPNIX5nE8ZBoRkA8fBRwC!L%KgAOV%p#w#*r6lbwjt$U8<$2 zwlSu=tbgnvSzhdJS+lr2+1I!$GEw{vnLci{>_c2f*_1ew^l9u)DH+p9s*V02Sr^p` ze8t+QxH$kQ*GwmQh2#)SqOKBIEf<@X0y-oMzcC_9-zUjM(9Lj zCGwN;6e4=EnCs{~#&8O94UlZcUgBCnKnx9>!ovbh@Pt4%{%7DG-Y3wE=o{EcYzYv= zg}^-WZh$5$0~aW5pb=dcSVSur1#}LhgCF*z@Ly!q`@b=U2L#NDKucyPu)ME^RkLSd zMc7ZqdS(#wKE$mGAPRUik`6JL&yhrkR-K2oV0lm*YYFQE`w8nk2Vp0dG9rN?9clb(qa$_~XZk}XO2C`(ODm3tGn$%&*qxi?v@@TMG4gr`L)2c@4= z?rStu^&ms2-rsnux>=@4{WepkX`3a|Y|d(>d6l(P^F3>mW^vYf&8N)48Z^_Qc4jPB zUu>jTbx)V5uBPTFi<5UN$`i}wr{nL-TE+H|{*H>0)JC)ruL)l%S{s%kx)(|d`C!NI z5RxOD6?|E6E2xI=)ePgW(=_2<(j@bvgZ|{74Z6)A85}Pd7IFx9n@qSq?2vF}cw^D9 zi0dLzUN*aAL_)s+*5UPm*Kk+3^-GOWgnrPYBZB;s$5H={Rsk5gSd z0xHA3mF$iQ$$PH-#BA3fVuY(DvBcGjsC3N)o7;3k?A}PcaDO3Ad!*z_?-a79?>@=G zi^)THD3wi&q`nc;sgC4nY7=Rrs!0@VQPIFI$Iy4Ft#mPUhK``GLL}T3h$=i!QxFyB zrD&Q(=lYZBUjEtiNPjiG0-`h@Lp*0VtXtUznH7bMTg-!uHfS*OH|r#GJSQ9Z%>9mZ z%9WOzcBWN<<&i8H>rBrV=3PKz5Lu8#RG>Kxr& zbTo3d@OSuWfhm+F2oD*^-xG9(C(s1AH&nB^ca`DXw~A8EL-}ORcbT4@E?dXGE^W&m zBaLFulg6?Yva#&nvRd|a`D{*+;weY3{KC1Q`o@{5{=tdU{Nk+BRB_5Q^_=XWd`{P( z6P%$zr#Q!htep2jy}2WT`g28^XPih?9y?s|o|PplN3$d-Di!4-X8sc91@1FOFk2g# zj6j~<0AM_|lsbzyAzhv_yf^lr@2g|Icc*QYXSL;%TVihKZf3fREj7-@5aV#nZ|H!9 z8GB(pj61M1#xIz}WWx@dQr#2Gm)*lGv7Q;$nV$W&pPoDR-rgOKi{4Nt?Op5C_#Qhc z?{#Om@3J$-XK)sHRjxv>z?J4pcMb8)an15|a*gtxa_YSz=ilB>j)7j%F~@t?S?7J` zdhRn~H}E;09Yln0I=KZOM_GwB^djm9{efQM$NY^UXU_QmiZo^HL?f9|Y$x+A=NdAN zcLYrqECwG|2lg>ZYfhQ01-BIN?TG3h9;tTo+?o;mn?d*a?SnD?sbG$vCYUQo4T%vP z4e23B4jn4E8#+qRCTxY^UD$EK*zo6q=m=E!J))y_H*&b}YSda`^XSXMWzjc; zi=xj8v!ZtkKSvD_=0te~og-HX*bycC#bIjx@sP>9Q$aVlJJjDfU6meorA*15BVn)t zLNBt1AB!~RHe(jEG8xB^p@Bn;gRok+h+ad7(`_L(l_D&p1z%0J!-L45zPrSJ-y~wD zFOulwE5%cNoA6LyFP!abhbQsbpWpk+cfz~V*T~z)x8K9}eRS{g?!$!M z8s~A3%g*-*Z3%9Lr75N}E_Qv?zjVH;_d6EWb#V~YQ|wDChuP}N=UTUy-nZN;mRj6D zcbLNgq+9TLo9^$=3w19(uhz9KIIMFPRO!&7Onusy zMf#+#I(^i)C5DXexM9?famFh@i;QKzI-3l|=S?A{0`uIm-R5WIF_!PYuUf8Gbg-_e z{A8U|)yuZ5`n7F#O^97yyU@O`)@l!{>*Lr_chDi!+8yh(W1L^KZ=D(SVXo!%Yg`BF z%`UO79p=$p#LD#D+|>rRyQS%l=ZSf}cbK)0Pi=3F3!I&Z9IPoh5MufI`NHX8M5zA& zl>*V@um%T7WAwrkio+dfQ#-&2eNcrEKiHa&tv@)CfUOA52UbTt4 zO?8Q@Q$6Q4R{!L-P}g!3)nB+i)m`pE)n;y(Dup{;c?W*ehto>_lg*Q*v$sj6v+jzn zqPGP#$Z{UV5kHQ=j3=0{uCv{)TgK{R3xd{bT1K-7n{BU6`wnzMHF1 zKhBk6IO*DD(7K|GF4rcb7&~C>hV3tpDQtq0xuh3AtGns!Tif1=RaZL3RZWKFls0?q?^X5}5ksHbefN*Exz;qGQ3CNC*cp&lkXUF z>CMa~fO2n{W6&n7A*@xLCG1nYtDHQ+GVXg3pSMqPkGEYmn7>6~=4Yy|2tKMO3Ks_j zgrblOqWsXV;&b7T#hS<{N#Cedk|oj4CCM=*lC?2kB?U3}BXfER^g5@_3lz z7Cy?x##dTe`u3V;cy}ANc(&>C+V7`HUEb z;!@mAunCS-vXT(h-^m+QCsGL2iPYKZeQ6KX&C~7bJ?YV!N9iG&@#!Y@;k0w=i>Y$; z+>{O~ebRiTIPsdIG_G8JJm!_GchqiaUicBokkA9-t3g9W|Ed&1h9aNuk$&c-NdDxp z#9pvhp5Us4eYm&yw>gt}MeInfhb7>&V0C0~MIW;~$Sl@};4o zg{}9m-L|Y>3v7#jEwmB8&e|3hv+Qk3me?1U5_VtNF2}{+jh&+_zd6lSD_m0`F7s>c zJ}gO_?(SXx%-uwn>*492c&hb1y$=i(-ZRFfzC|WJ-qJi5kF^xyq-8Mi$!Z{sw#j6; z!$Iaaw^03EQFMRo13ksP$Y1E;1lsxb2JYZFj3K0sQAeF;&i2njx-rtw)<_{5!kWp7 zFgCWvf)Fvz4(a#}#==ujEOIRkHE%Zs~|vL>e8V@xTzu z;_pN*@y{Z<`oH2){<*l9R^nB3p6?xf(RY(R=zB^Z_T|$z;Ps^M3_aSnn3nlc=}X=> zl-xU;8s&+h{&im_k7F3o$Q4UWh4}V8w%5Lw7PB|s6!2UygnQQN(%r+f-LbZ{3tauH zS2>qd?slC2{l;!96SZ=GrCLY*T4t3MKeJXA zvuzhk`rGc8-nEI#``g?6w%ao+7C8o0hB?ctJ~_A5EOhm&OT!3l4Yojc#T{li;bEGN zdB2+f_ARt#;<(L-FL0bBY|hqXSL{2v#XXgJ>M5hndvoc2zH7A8*U5hr|LN~VB?Y3=Un!XyPBq91w6ZA>$G9gV_h&hlaCevvsVd+>h)?{sT@|;STOH@kHKL zX@Ai7+6X+#cwrMwlE@U?NURG}NG?V?B;M!`(hsrYWx4SmWfK#U<%1KK%2Si>$loTF z$XUsya(40s`LCo=@_9)rxjpfRY*pe}S@Xo%vXX>GGIfGU%8x%HwZukA55%mLc%ll# zLn77Ux8VaJR{M}}Y4AlszIq71USZ<~q)$0p#1GgDgg(}E{#@21ZUGv_HXw75m(2el zW1E(8`v-!Zu)A+FwZrqAv|wuTsB0>*!}%LO1N~NG=ipuK_kHhdJA6}Yi+mkzeSN)c zS-zgOj=p}j9N%&q)3?dS_ARhQ`L^2--$$Dc?AT>qo$amnKU=lr_ZddJdu&PfxlBUBgPIr44z)3^w7R*j4qDtbr2Ztf zQ`gB&=~> zoq>9K0poymVrDT$Kt|e^knLQJJYbGR?9B7XXjp@4f)%KLL0q*D-HQIpDn@&= zGgu;9!=q}zr>~4a7oSvds?%xtK_kipx?}g$TzeF`%a6;2a*e=*ERD~V|8Qord zEuvc7IBJ&UTXd~tM(hx2dE94dr-UZ5Nr~rW=}Dn-V^UZ7*yQf=+~l_M2T7GOYhq{F z<%B!ZKpZ3mj^#)mM|}~+MC=vDhprKnXom8aDSvXKWvQIaqUEfOydTI4Ry$aY{3bAl zUgbYROr^*9=1?s>|B;EE?OpJGj^X%QM?1Wevjx7>xfw5Y>hUQq9#QO)5#L>M(6v4IW9KRSqJ#G3 z*t2{qti!$6%mY0ajNRNh`U%)G?L^np+9pn8byEjYwcXyMg0MX(A88Ypy|*qcX=R;W z{LUgOUT29Zo?__+$EM;X7QA?`Wo*e0%j1$F^}J3iDy z;G}035$3fMCHU#(qJ){>Gm=BJi*F&%Olv8Q)jiHJ{s7;#&c01Ckvy z9`Cdfl#3?MdX)5eJlkJFt%KZ6G-C$33^~hTu*8Bj?5|=i=ajr7ubKKJ|7oxn^tOH? zRrD_LvA8pme-rOWQ&aBA7N%{Iw`kNzF)8DyBBSv;#XpT-D@He7rZ}5XDUWXyEZ3xk z$etxvNURAb#Oq`Gi_S%U5-bi4=F2s$xg+Gm*sDc*(IW0^W>-`TIeXgr{~?|LhGml7 zU3qvql>3BbgLk26v1g9qg8P+@=iX9(8T#NDHeb64o2gC0rfbF68*LM8Z~bU&sctRS zPrn;{TxYN~hFh54umx*w9EY_wPR1$?*;uUMsY|Wz?)qAP!r4o^*D+mX$r)Uv~A;^s;-8rj|8%e6%d-NqqURr;p3g=d&whFMC&} zzZzS$>&>R>#P<&!bMwAAPk(ysdiCX?dwc#+&)b54=lQqQ-kaZ1->x46d~JUo@ZI|P z$|w93d`X4f{R0Z8`PUW>^6x2}tKeQCY= z_D6M}*sj;RTQmSt(p0hW*Hkfm$-GxL)ghs~2}{AKP{0b#L3%S+ygY*8evmtwDSw z-f(E-hlc$kJ7y1zoSr={a&C4;WZ&$&5q!hnB04wxY46rxj=fI(pSH*K5F1;kzBQ)y zU`t9yS95OqK+_*-JB>S1ZX1pzL5AI6p6FQ|uft;7=`y1aX*YrMQcT1a%>!F4&1q|a z`juskI?nQo`i|MG{>%JE_0W7$)!I^}5-j7?R@)nO4|{|Lj%clE8o{XtM*N{(8Zkg^ zj$8)jRj#R3pmzB+`nu*x46Yp-+d#WMwx9M|>`XArv_zX9+e3Rg)~rp4wQD!VXtZ5p z-e{~bcQg;8t2FzgmD<0e)3isUCu?2N_q6?EDDC~2Zn{CSAsrmIO@A`ZsXrgz${;5E zV=yK~8KLBjMkEC_)k|G&dXpxaj;60Q*Qk|f`2*D2OESF{eVu;R?{)TB7lA&yrQR0n zx_ZN{pX+tA#$`>icFme$?VOckot`z<`Y>ye)s?luN@U%#Qdu9Ym06Fi?yQ?uZ`Mic zpIM8ocvg4o_IkKARCm8cQ#To8xXzmsYBx83$#`OFS}WVMHGP+{EX`|(Pt7(=NS>^( zO5CHHnebR!6sOSkjcut3M~_i|kNTqe7P(RtjEGhxM?6z*u`f_Iw5KW^HjDCuElHVX z*DG(^lawPPhAWdJw=12IpOm|!;#6IuhpWWs|5W2*MAg2SR%%zwDs|h~6Y5T}+tte0 zG3x(fV$?Na4yp!52b49UdMJ-aTvh1oKk+u8cds?4%I_KKVB>Yg$S3ttxV3TybYE@< zK-sTS6!bz|Egc2Z<0JXnToy;sO<9s$%ycGR(654WdQxBlrS*HrYu?4=QBNb#Uxvwv z?pH*8_bEc@-b%c8ts>6277(*tzY#W9HsN%(BfdIQiT|8N;)Sy_5#yRov~bNL;=yCN zb0YB%_});bE419vFqBa}GFYeTdZ4g!P9RXZHb7Kv4J@r(7|5+?8~Cl_t^Z|tj=xs9 z-T$KOvu|&i!?(SxzQ3ewynjad1ApU+=7GtTWdW%wKX}D)IW)?ZLwMYc$j07s67%(= z_WS;!X8E5{tphyuKCqNN7xd8gLtUAz#9L+}*@4|e9b_-lR_+sXfP*<77tKe3Y4-m7 zM_~zHOI*Y^6<6|2#DzRBbmTh-Wn3-3K9|RiU`H_*89klB{3HeX5kb(aLhI@4fp642 zA58t~`A&3py$-E#$V0m7Nx{#R$w83 zxy#9rQSM9BM9-h}Rc~X)4)(p?fz9mBpv3Z_TAYmB!2Lr8xfxV4Z>1CX?sO&BfEddnA~Lwd;dk}|k-=`Ncu)?l}aDNH@lPwf@ z3kkBR{EM)YofYoR;NeHqVo5{#MRlmF==QG{s=d#6gQt{h>#frigh$x z{+e1@noMPsOe2lOWklzq^~8h1_QbG4InlK6La1Ni?9l$gB_XD8L8w*HjL^)YhoP@U zDxzm`1aYyr8lW0{MP0lGDO#V|k zmAqRz9<0&i`O^O6nbH>IgVJ{7m(m%etn38Yri>vsmGz*Ava!^d@?DgsLPcj(_M>yE zw$n$d^-QYsZ|1tIF`McU*bCl!+$jGzJ~3z#s8FHsfqX6AqHjvM?540xm>}ydt%YvN zp2IQ7W27s#6t&>3vH1!X+pgR%U#v>Sd#jh@L3IH>MAJ&~Q8QLCTsuzjO}keyNf%Jm z()Uq@^{}IH;yrYMeCv=+>eY8(-ms*BzS51{~RKCUDDcWPT6iU#8 zWYBZC9D9ck!2I|*tcBt!c3Dx3#VcFLw}9MQZIw%2t!jf`RPV=UX{zyLZF7aBU8nHt zZYi$lDa8~+TP189r)+ARpd4?UsoY~+s2pLOq;wdvm17P0V1748aZne;cWY=m!ziulaA1CsWTHF zmY6Bwo9xYSYc3f6o6C@y`JS?kd=J?(zPIcjzMpI`-(6Op2h|!rQ3mr&IF}Q{N4e_o zWG*+{m2-usaZLC$M}$3Gx-5quA%ld|vKK-kB$MVtE5a2}Sat;71OJN51WcR>^8089 z#UZRxIZM7;oraIl-oi)f=PNcFyDQ(Dan%p&HPv-{Z}o)8D)p_XHJUrom6|y*9GIzu zwclb)S|+Bs7Kxp!tr5FlJ3971?aJ6k+Q+dDZRfZ+-L<&>IyUZvZdCj?-PiaZIw(QZ z(eZWkZ{m~n<3aCT6Yta&#vRbjjhmqR9@|3)&M~?-F&R2Tj7%37y-@o+GFQ_i0@9qd zrK&B~L8?XOzm%})jpC`nsL&hklHy-;UBz=CR=Q!_f*&{h0L+Hwa)si^U))a z9bF2oKo&slkRDJ+q$!ky{0e=6`$N~^=}Q+8QU#pj6r?rjcz4e^jX}FB9F?CRsn4c-UmcB}jtyJ07K1?+| z!l&90xl{c-3f5R+MrfwTLRxp+8STV`6y4dx1G*bY(fWhQ6ZPFvR_U*#oYc!wzv$bh zeg*gbi+Wee-}*i&%k+OGC+bfnZP)b!T9DlMA=i%j;pa~No9%bs;Xz7pqy^q zstB1s;d!RIxMciC-o)5OKEm)5yQg1-Ez~!{2I;NXaD68BO1~a^0KU%~QMueaKwfFS zCJ$N)#k?2M1P9{5D#aK&l!E~U@w)P~~v>U4>* zdJNQU_>>&O-88weY5HHrZ8dr0@mifs+cLJ9CS_hSRc4+yg)?`VN-}$xmS#%E_ZjDm zFKfjbhtynbcvyqeN2UFyADpsLw=bzwdnduB{VT48W?jrQ_2;NHs$V1DC@9}bunZDdD+d?d7)O0u|&MnOulyR zA$jLB@?YmVGSvx@UmP2WyN;#AI|tb7o$bkQ&Tr&k*FfrlYYQcFU!}6#`P4FZ6?Mw3 z1U!uxdYN0GR=J(jB{xsC^~BPWXBd6Ydx8GfCu8#c6PbvhitQhI#O4vhxnmT~O=NEK z7H*5+;QNao#1v^2plJ%g!@LCkQ}!F$7aAtl!3PvYutRkcDb$QWN9pv~S^XaDmBA!` zU|c6(YI-HFHihNc=Fa$K^GbY(I=j>2kdqu6QdthjC)swlN}SMath zMWM~8xMw?yPqwwf?^_|f+_F%9(Yzlso8F*<4J@)5yiBRM6CR8mla9ih zMKL@KkeizG*SXr9ovFocBHJ+CLi6bPfqN9`lT%x~y~#w+E8-`(2l37^#C&kSY3$4< zBAu-WgL4?s&$);&yLJ;s_rHYTen;H*VB{dLm3-|*$)>(Y@|rJ`)cC`M)_7gSK@x|xr-XXkfw&&xmT-jZMD{xe_g*_GeH^FIFon6dPF zo_?F^HUFsZTl=%br!N}p&nbT5|Fa}5aKChO053NO=T=+_N|hr*`>NxJx=t@K%XNp` z?(Ri>^<1JZdL`xa{)6=JBn}8l;lrNFR zeC=74ZzH?OXXMWN4}+d=SH4*&LU>Ai6E0FW#Ba=HDULq@YNaOt<$Dug7Pf{DAS8Sk z`wNLuB%{YwC8$I57=!hzF--!d2D`z@UmN!H&L{jE#D{y0)0SsEywSrQe? zEeb`nKzSAH}DeM&hlEU**sAJT^rakM+_%L4Vg2pl{SAs9SXa-Kf-{=kZiz z7REyjkaMzhs14w5mWzK2&xB>%TYfd;`9ovYgt3DvDZ4t*|hy!tM|RtJbFj%c#TF@PNFJV_?H zNV3Y+mRjRJLdAOY^gGXZdW-jOx{dD<{od!IQ~Y-3SAP;S*{^4I`*G%lU&VazM==Zi z$xMXbOMmz6r~CV+(c8Uk>7O1As3V7{`Jn!q==M`@T~YK>mx&(Za#Cq7kvi|pqQU!< zzUJ&ki_ST;+4Yrf>*~&cR5Y`}J(b<)F>(jIxm>w#E59?)NN61j3CD;}B2TW6I@9{_ z1?E(^3s+CJk3T2dE;NQVipQXi(sO9PbOmxsccG|oB@~v*pfA#8=&m#uS}*m2dP(b` z-cl(vQi_HfNUdQ^%7BC7cgQ9F2X&V2LFTX#1}++ykaa-T!jF+|fQ6VWe}UFeoW)wG z%H(}CX2l|1igK4hshV%PuWDo&rOvmy)y?fwG;<@$HTNUawFsyaCC7XKwInUb%|+^F z$HnU0agn-=_(YvK9@CwPTd(!T`ZeEU+G~bH_gD9doU1b1FDZ*Hw-pmjoAJH+M)Gr- zx9D}iDk_q1fIFaLp;HhrLIcah3!zwi&3zJVtWG#i&*aBbrQAAlELR2?RKE~9Fi)li zJgPKq88L#3CAV;uWIlJ6>coEp?6Pb&PUy`Y6DqYn}r)p^scqAdVw^gIJ&EZ|1v;q%F>_^!e(4 zso$znsG^Gd^k}hpT8p{@t%gUaTndQk8T(O42D?L<9)dad-btS#b zF^{?HY{c5#0(;hTi|gWB#9#Ag3)*0wur)MNRFX0&o4PHHqz8xhG2g<=*a@;aoLiR5 z4S{O%ccIa|7y65rp!a+vtP#>-qhNzC@+jPZ*TEhx71r?e;XgnQ*TpY{X9`E*HexB< zRqBfz3V%X6LKDz9q%M|bsGv)Xs>m>NXLP>KywW6>LLQ zu|OWi8uRf>`Xlne+Lc&s^$N7Hawj+|KZILj-=JR+m#hxdMAift0CtPFB&EQJ+quSK z9d?Oun*Pc+q*8bTxs8h@I&p(TdhT`b8rvz@m8}S1?AHLp6a+Zt-#{X}KQNvx3oK@9 z1Xr+agE!e(p#O6(IDk`y&T_3o`CyfDw$M-RSumd)9{j*11aENP0ynv)f$Q9Qe}AsZ z=Vr~myKF7*0(O|EC41YQ!nSae;O_i|>FUa3;#~hRv~wGC*}0e*;~d7QoI{w;jFF5ZMPB^Pv3!r)RV6;2N~fm?+e!^Utc*c@&KYs0N! z-~fPYhL6Gf!k1v3>?Qn21|heg$p{U*ksNdadKbg782k}-N-;&=S!KkdG%s*iw^;E- zAE~@yysq43o~G(&ODb?(V#wv}yvvNP!6DTuas+rEpGYz@eJY6*!)MTOW)&C&h zRnf?w%B?U1=4P|xMY2@%OPGZ2NngRMTr6%8O8Kq)DRw8fjV@y&sXy6jVj(*@l*+CM zv|~p4jC4DXi>&8D$nK7L1XQgiqN`4X>QpWY4XKzBdRpEt)V3TCeJlGIJXCfpIJ0b7 zaA;XhaB*43;5V?Qm2U_(t0)cjsjM41U9~HubC`*l&LhNQS0A#Dhaz*mb0|R1p_2m# zXe8*Q-vyJHsi6@}DD)@u8}XW1PsD+<)GSsa{$^RQE)%;z4R96PJT!(~9qi4P26EW0 zfOEIS|A^hp#PV1Ecuz);)M@YeW2z<&B&&&yZg?>E#oRGeL&$I@(ibMIUJ&M}+b#OM)9J zCIm;7mjN`u{@dfD!KTj+D-{|MQjr3w)7tpW&g|71Uq>p*~ z(o4Nv>3QA+y1O@m4tko=b3LiF!|kJT-0vyB>jt&mb%>hano0F{HKtm-GN?MPZlH%Y zn~HO-phmeCQDdMsuGYW^v}a8Cnkz?jUdRt7tvdWo)^M0&XAI34FbPZxMk&~trvX}w>hANgA|-2*e3 zU4iXPZr~X6IPf1cAaIiT*xdSNP48}B(>DpjQZE1rTzk$ zIZM?6(o%tu>1BI};*v&0$CAQOY{}2G?|YM zw-MHc-wXeRqr|)61o1`qn{Yea8)Pw_@V0OU|4!<|9gzmIBcvfryflR-#0S)8aR~KM zjHhs^6*XM~f|>A0=1^F}HIwD?0ofbT1=W?sBQM~QXg+ovo25iSeRHM4V+botEVIov4Itb5NKT{q6m z)gET*lDW>N5>IJ@aZ&0U(N~mLBQ`5ataI@ z2ON)ogNC5TL4ss8a0rZ(-UuDVpx;oAxy^d0lNzAyI& ze^mIZevS;_MK1!)i)F!DCH;b-k{iJXrDAYd+2qiSa!+V^MGTQ#S(}(sIiDaa-xEu# zfet_q?IQ}Jn zIuz7B=X7ePtCVWu9zef#-=iCOy!2MjV_FT~!_T~Nj2p}xE(AFXUC6;rCARWg$r64g zWfT_B-G!yhQDHgAm~Q4Ki|_cL*iM`)od6y$FYr1Hg}TTDI3zoWZiXV|X>c$62|Pg2 z0qLdOh4fGbkTL4%=-(O?b7^z2Hu^pCm4+mIv+*!K3(T4HH`i8|(r}bj(|n{PrLnB4b<+%IY&P%9*lpHjJ}`I6d}IDS^Qt*Fv%rkiZVU#| zMp~X{*0;3Iq|I$J%FVTE-7%-v9AU1k5pAB77BFd2_nRIhcQ>s_YGm4+m}PFaD)Yc;X&$$Vq~ zv(C_nY4xHblj~PRmNyt3btyY9s%7K3(es;piC)~aB095KLd@!BLt}0<`z7XVvzVB6 z&B*8@O>ae)HW?RP(%2n!xY3BHPT993Uo`MXa9LRq)pZx!AJo2X`!hpr+fs9)^<9lU zmWF8`%*RtYnQJA3X_Caorhbq!W{j@garMx1XAaS_v=;zzG$=f z<+>GdGF`*i{@VM|n>9zGNcH{5&+69^PBk9!Ts_ymL4DXZPMv3Mraom&R)4k*QRB8} z>ixFgH2dsc&7p{C+P#slwf{wR*9p<@b@OAh_4#pk^`7{a1~_q%Av)=zp%R?;Hzc!$ z5h>Be?9}1LXW*>gK5d`TleW&dzs63ZCjF&xSi0YMKV4%=s#(i4y{5&qv1XOAU(Fvz zD*dT(NBUYLoZc4j^1KF9+7g2^C8U3nJW$^}DOdMvLLJ@FxQW_su}3sFqTOmCvX8oR z#7EUmTY@Um+8Xo|{sx@BY{ggOD}0@C24ExB!!H>0_}>OIe$5bzD~)yVgT_I)#&isy z3Nn7}&54R3mQkSo@If)x)<*f>eoSeMgu(1cvI>rFq?!}GRP`=;tEz8Id)59JooZT4 znbI4*L>U=PE8?O$De6Uz#|is>c}<%Wt8J-?)i(`BtMoIGKH9p9Ew0C7`-+Ts2pRvw?o}cKQaBNyRex#9sP(s2%+wSVGkZuA#06#!;gKO{t^+ zO9uR3$vgf#TgBv@;L~-Z!xjjYbGvu9);GsCxzy^ zpwL0*@!(6xFF{weGeB1z3cRW86Sx9oP-w*!|F-f){<`H;{eiL>{(`ch;BkV#Q~51_ z9$<RlN$b)k{K4K^}l|K#+vsvsx_9E+LTXBQ9<=i%I z1h`V+aAeo6MAJCZ0pk|?BdLdU6L z!6sCjz(1tVClF1%1BqYUUqbzytwLR^=LXX&4}de{2fwWp@wY3k?YmgG+}r1;)vNz; z-sAk%*5fST-KK)O?kV{r-QT~)xjTJ@+#kL?a;^EY*wy{ZSXbjO{asDJ40QeaWr}O| zml>{8U*@hiILt6N^abH;~5&OPsUIX}P4ahl(Ca}Ism$H~5_Toi`!X*69PoLlJ3|0=c=?u&&&3#k*J^luQ?Nq59;z&x>5S}XPd*+rQ|^2bCk zmm-qvR>8s0{BXJ(zlvPVJqtZyn+3DkZ~og%cV7h4$_&wU(MzRYpP8W_m?+E&5sYK-yWolJ-{brLR_Rq+3-_r*BtHp+{B?p_^63(TP>X zRB`2b>T2ai3aVO7Ew0)~y{$S-b+4|XS~$kiBb-5ct7|&*#LX}Uz}Y(IyTJVwILV(6 ztrIShIpTbJnAC~Q33uRU%UXzQpbp^`@Iq)JvIJE8nqdm;gZv`K<74EP6fSu?Wh?xs zay))PIT)XLMyBXPMhAa9_2CI3yiOWs}CO+HYWCLgC%$oDBfU>@Z;EKzk1>#w?x zT~Iy5DAiVsR&~d2s?xC$Dl=wLdC?-}E%b`=0Q$S~5Q>1uIf}(-HU2A_fosu0@(;*G zY&8-_n*lyGjQoi_hU1azFbT7;5}0s2z(ex{P6otZ0$zonNNsdBf?-bNCpH{?EWe6g z#4n;F6}wTt;uLyEnTx(wAsDKeh_%v|V*PZ3r!(K(a(W6*w?52Efe6JjDYN%>y zKA_TCZ0bDAT=jnIMfEh>b9JQMrJiMPu6bx5qiGniK(i*|qGoNxea+B_vzh@B2Q-5s zhG;77A+^pvOKq~fR5>j5R9DQ0mGeyniXwweq1CUzXK0J$qB==_2V{hwDt&0RqAzMz zlp+i9Ge`u!6uB>-3|O~QkO%T%hzVbYti?$LoKDfv%B$#lRX@zDc45D0bL2~PDE?W$ zAFpRb6l+b>6lx2pIB4Ca6l~cl+I~#+PsArx@5mpje)976$J?BWUjb{guH`oFHI>SLH%^duF$|P<(#Olqx+mBT%>WEj&qr;_0mu~mci18q zphWBg^bO603eh6yUo;k;jCO;YqkUl|ItH$X&VoOn>*0RbTX;35Me;B^(p{c{+>`%? z)W`cH=kbmRiw{5&6w8n?iXF&biUY_Wiakg(#UF@TF&%k?4?%M91cZ^7!mZ?o;hDfG zk&8ybF(?hKN8Uq?ki$>~JPJAqcZ6=ib08eag{C4cVFz*=-i-PI8+b6{lncl{#RGJn z>L08(V2{_IwjVex`hlMlHXqK84xTEwGEKJan(> zKlGR?AAJW{=gDd#c2`{oyQ5i$Nm@O~OstWcjVOM_v=i@c;qek{4@EQkIYmZ*@^ zq$x-K(-0$Hpnrm;>n31nS{pW5lZ&1Ktlf{Qu_&u-h;~%gMPnI`HfWDF4Mv`T#;SS;b z&_}5S5d@GJNX@)2#1ewS0|Ma6Y&f@+bxzNReli2ti7Mmps-BSG#X$Nfew#sx{ABEns3@`#p)J)5kvzpfc#ga&)Ci4}{RU&<)nJn7t#nWvE84~J!am_Pa05m0dSNZ676x!- zzei4R9Msaw!yVy;3L~IS2rC4~LbPc{EX%H+t45=Od z2dq0ta(EHqmk9WVG!i}vx?l68CQyB;HJI??rN-hc@q$prw-Ls0r}=|SGXIG>4{DDr zyCpP&ap5CxJ^~q~;tpR2#r1=uC2%K2aX4 zPm*JL3frdJi*42#v2L27p#QoRu_=pSGu{Z!!Foauk-oBTU^j}C?UW7!qC9v6=)bIWaWF4Q0 zeCwG*Y;hNaYP&jy_Bs9yHmGI;)s=k%8!C$Yeak2MdzBUYa!Qx^u9md%H7!AWuZxSk ze;4O^FBZS_el9NdHZNhld`WxXr_$TLn`L(Y?ef+B@`{wegsNKsyCWxf+SxfY*4=>U z?u{fJJ`edz;5fA}IEvmF(lE7&g$xU7_Qhlkb|tlz{Yiacm9(1kQ<;G2mC5Ci8tyXj zja?Di#BK^UVz&pJ%vAq;W`qxC#(VSVJ)VE*c+VF4hWi}d7Pw1d+zxt%JA)BGUGFc? zLuRCx2F&%Atj52OrTjs*4w!ZSEp(1+NW}4WauM$&-}CnN7)x1I!}f z4YODH#GDignG?cu<__RwKNdDH2Zia(W??3CKv=_E5&mXA3b&aG@H{V+0FHKNc8d6w z-6@XZ4vTvJk{IIEpf|7;*r>GOY0_rk3iSah%rCN?@H?3w=>%D^{h-tZ!N15e;0|C9 zE5Ob}9kJTbOZ1*>ANpE$8f^ewK=(mg(bG^m+7e{IPRmBZ2H6;B8lZEtfYNhgi-jv}6~CJq#?PW(a|o5jwIX`6gMxzq=W{uI+53=!JmusB zS3KymFCf-d-wKVdGKFSTo(|rt7#M6+Q73q#JR`WIJT`c!JS|9;FA5&1kb>JP*N6V7 ziXhfi9|qZ%`lQkoBpbRPP#Zn-XoIf~v(@hd{k*-bGnm1-fD@pKXw2Uy_w$3O3jP&f zpVXq0g^~1FVJ>|}SW2H4CerhSOuCa$NYxY;Q!F1rUF4sU)A?Rx6MiQl<39q&P>;}Q zP8K@JeG0ze?gnB0Qm`q1H8_{|1kdryLo8saEETk54Y35|Fay*-a z4#H=srnmx5k$kW&JP>&k{txLYD?`@FQoxQd0IdZLM|(j1&}=9cm1O6UEwUU$47Whe zhQGrr!m~k-E*ril3D6p;0NN-?P`*?f2IgKcQ{4x?B>NM73;hRsK<`G0PC|NO7W9<- zAzE9p4%4ef%VnA__-kzq#ZLWCu;*@7x=q=tOv`1J-l_!s`I_o=wub5-wti~4eW1F& zy}25|x1Lel_!oNb^#KV7!k1Y4{+o(v@Lh%{^39 zO+$i;Ht>J)+Tec?Cz}L!1$^!z2^iFYa}NRzF1t9EH3{|TSbjFylamv#*~h^h?7P5Z zwt1il`^8_6UFvVi_V(M@F@AzM#^!?i=GoA8&_l~(uaM2S z7t{q#qQe}-{>DFH&+v;lCm-Z6LBU4|CO%1s<{ZW7yq3N^Lp^nFqFyT*V1SB zKd6=bKjch4NOb1Ip%}hvD2a~<{l*srxAQ}Tcli^6W&B=$0)NQ&gZssIjN9sa#`W<} z;ztB(2!95_=WOVjIFRfqO{88+2k9Q+RQ6tYKc|!d+JWr4a8Pzld?dReeU@zq>mgun zgFM`pi0b+U6gOaW-C(VeN_L*n`&y~MqLT6G%QhMnnXn{ z%R1$EYoT(D-J)t2xlZMb(yQmkOi(*wkEpfrPt=#=^VIqAXVtso+p1;p-&I)L8r8`d zSOrB-SGJD)q*!E!6|bx@c&25Pe5dIlW;Z5b7xhcf+PVVdh^8&lLwyTQS2ck3%Ht4= zTcA7gxw6UF-EdtrI$RB?WCx)e;t-iv$d?8S8R8}W05BGcY%o^y3R1XX_uWk-zPlkqeRqq3Tw-fap{}M+X z0iuahL57_jK_2H{ve0d#wBEJULZ6+c{BP-z!R^e8&@lEFGJ(5Hz2{zme$gGKy|9x# zFC=hr;vR0Fn93K6L-<4qmw~>TS#}Abg7E25R0i*;zzQL7)RC-HxLcQ z{7_4Ae5k!R6=W|ig)WPkM5^?bI3TSe_2CWF;&3^Q%9^t$WDB{b&};rJR8JfXuLGxz z*I_GyLK_hcTmWpK2DB;Ys((Zt01B2207PK7g z3EZOyx(L043`TDw1A&!v515}tu`kFvj6`b4ZD^^y3z~}`Ln(!Tc2sr5{#38Q0-85~ zRZ~}9r9UBWYqa7UO$+eb=0g0TrJZ7-b*A9R4(Y4V8d?wXSY-!ykcRLCd3~rc+EvyaUKHLWI{-Z2xnQS{5^cc2 z_=^^S-%-3I1h8kNxif_oQQKZ1889FF2y&1K^cj2Mp1zp8*CeZe zgg^3K!V~yz;Tv3&u!%ELb2{27+8w`|u(-UG^0=KwyT!>ZyoMEy2xH7vN6HG4N=`H)t~69I7F|B71?_WV4VyVFKDE^^`fqJ;029 zUHDyi%FW@gF>|=V)K0cIbcNX&ctQ{Iy$3nFkEGN2n0Q}(Ikd6zR&YT1x4?qZ*ueMV zN&Z7YL&okj?lDB{1F7N0flkbn>wZ1nc zxW8%H4gd1;&4Hqd9-v;$2U8q}LjO8P5XtUrGRNa3r+7C}i+omkgMS&_K2Skl1N}lY zIEjIRTbbv9jm)0FRAzQy1(O4Mz4HPmm|20VOv}JSro_LE8R2ilob=_>`QGjHB<~VB z$9sUD>wQjN1n-~GzA;Q+KgNy<>}THvTX4S+8yv3~do zFfS=(Az;TH37pZpp={v8-VS!>Yj7pFlN;dEa2h-xZUfhchl0GtK)4fd1J?%jVgtMa z7=35Jilr>Tzv>3)NV6qcTqaHv7YMnamf8vA$G`A2lg;0!*K#?OhLe*! z*-aslNe)hB?)eMpbYE}!q$i*1g@31brMZ<5Rpj%p+eDa31dj_;vmGj$~cI z2eL8Kn7v|v9VNX5^E7uw33wBB0?YjWQV`34@%SuMAK1xH$#^JI=7pYzA3%e{=b)p~ z1xP97LV~D(CrSa8U&^uuA|=(5q*KS!v4jUVB6$x zu>p7!c?dr){~IuEMk+ILzj6j1tGa|kst5Qj$MJ_8#p?~Li>J28{Ig?xiN6K{&IQ&iz?RErfAYL#+|_LNegZ>~CRxUFhp z>Ztx;ex_bzt*wc%FV<|0IIk&-3~5rM=V@C2PgV0+wJss9iEew`Xi$q8pfks5bo$uU z+8xmqnkG?gHQtEz>bmx~Dy@}O-T`$tBk%#nYv;->s)pDb`CDWd(i^q`r?W?x5Dv06 zrBSqBFpy<@SQ{J!-m>gqtJ1}R7R4|9bqZlW_M@)vX+b~lwy%plJwM-Y;~z;^ z{`(#->TQ8@*_-jsk*{&*!dIjtkc&FM<|aC$Uafb2dX?>pdgFC{dV9_7dw<9?`{POP zs4uU4lMB)UlYd+dek!U(Tqv7G4yt-jy>&KV#(9UacLGznmBd`$Ko1j^v036F@Y&x- zyd(W1H45(yPXV6l1z}7!Kl~MZJvKZjyi{rz?kXAp%jAZ%2l!+gvG+tDJxa`_(#02~ zLSzY#(2uw+^01YG(~)N=7ST`V?Zb0h~B7rrUH4qpNF z*%vam>^i&}8jYsF7^vSJ#@(<(F$Qrdb?7(MR`jmA3Y`!5cRw|=z?uP^Ps1>orXKc> znnzcwRamBaEOuFS0UNHmiCI-Q&jH(E2}ZCRsRKM><;4Z z!DFr_QZYi8syt=*UDe$DNZr=@Q*+dIUCY|*>zYJP*Xg5<>t00V>mEdB=!;?===E_E z4ddfQ!`XyI#>0uEaaYm|)6?XT=|jpY^O97?>`P6yG*4@4>7Lf!5}gKFE~g$a$E0>L zH%ZAeB__8w;YlZr`3dEQmGO-Y4dUMFYs8M!&yLC0y^3CYZBE-7aP@9 zH##aC%w~1aRYqUZor~$9zY=>@ABgL1n3~YcI3}r~X@5#1^OLk+ES8#`tS2*C+iZ3E z+tcbzix9F}M?P!tI&xO_l&GJLBBHHL_D0ulip3;08y54b+18k}<~L$mG(Q((X+A7w zXS2AN7fruLe{b?j^ufjlqpXc8Bab$;M%HRDBVtCD-~O@gNc)01Pi(f@8MezA2dyh> zMOu5;TxUVk%@z%q^}n9B-@HBTl6hd7%rYjersYUlmgQ+$CkvA{!qUCQY|EY+>n-nU zoVR?h@zrvo#uv++8b>W-YYei~t-*tT`#y91v^M71sZUJXQW}`{CZ8}aOL7=`B}N+5 zpl5#|?!L|xTcF()ZPoUOnyMKac|v_ALQ)mmud6bF8?MM!4=jc1lg+3)Ys*kQuys>4 zwXae=wf|Igjp(bkMSfCeNA=VE7kx{!BsNK#5`SO&OG0m5t;8$3s>Dcr*Q8PUSxMvd zYm=tx*CcJxuTFZcKc19g_>|PcP?prfa5Kqfn3D8ZA4=?{Pfo=2O%kr_{)*4mb&N04 z#>Q)O4dWN-S^%c)N#MO(9a~E`AZCKLbM#%!FHu7^y&`LC7DebZuk9Xniv5Xt4#*N* zw%%1evc#z_n%60xm|iLfV}yb-OvXvzA?~C9iRtzKU@H9ztgpT==F<1VjvIPnLyh$? z(U^uEGj+fwnOkBFEHPM~r5o1Ux*L0M-HP?JZO8tz6=EJ+s=SH)7x@xj?@YiLQtE}MgBz_bHBWUNFU>T%?x_C9n-og#apER$jtS<*522XPR# zTMPlu zszLUoZWFbrEd)(AB^dH#NF>Q%3E4P!m7E)xOdj%MSg?i-llt{g~nrv;k2lLNzncXpRME|BSN5pcLi2N2KjK$K@d z!0#RiURyq}#{CNL_{aFe&P=|xvm8Icv4z`cZ_3@WrEzX+h=r{y*(|f!_trGt7cRqm zP0N0G50+l>rj{=Co-FC&jVX!qekuOx`Bc2bgOs%Q%qi*Ni78#+Aa1P1Yri(zmjBveYw&B2&HnSfE&He1 zZU>9{rMD0J)z|L+wb4E$>wQO`CI)ufV*+1oZ~aNOJ^tg?A%4QD z@K3jV=Y!@K{895xeua4wf5AKiu%`y`i!F0`(t3ih<5$u5>sjssq~byfu*XG;U$*MQ$`pUp3Eu>4Zcm2=cp>SsKy1N*$U1A4Z1@C%m$ z*hJ;S!$S3hg+fCyB7$(6R0pW`O(ccfL0SybiUeemjzeoBgu)2!S2xRy;*Ic?s_f|OLy(v8P927k6xk3&13}L*h zzwp+n5xP6`!oMB&!h0N>!qXi83lDW%4yQXlh7l(wOmcP;J~&qhom|I+yRL_V*Y#V7 zbr%Tj-LHgR?$1Iuw@RGlt|lIJ$BL)iQQ}E=Rq?gEiTKUkSDfqKC?f8QqQiAieCRqN z_H^A9JG-8U%UvdMy{oG9(p63B=&mdscQ2P-xqnDy?w?W>&rj)=r&i>o_hKaCBjw%P zI+^8@pya?%!l8=PX!&aOl*$?#VyDR={eFiQiSN_n&>NeCpsVc zi*{7RVF~a^>@R!@+kv>T27n}e2c3zlu)cUXtN|WCRd^WW`;uVL(nTG8P^#uMY2$ z#|aAPjMxndNJpVTa&3hldarQ6i{N@#XJk1+p>u&gF@pIYHdECFAE4oJLA!+*s@IZ( z4gVv@8SUijsIF8b`V@66CYL%FQ%ZG;IRQA^^(k{y9%(TiApbQ?Ah+t9lD%|Z;<4r& z5mEIcwku8e0Ol~BNwvbQ#9}OfrK7{ZtYsKd3~~?E&>!$N^f3Ga?F@*HoZ=$-Kyekl zpg4~{QEW%;iW_K67{b=T4KN=(1e=7c!%iSCv1^EceM4NB9eIv@LQY`EkYU&mgh%hd zr_lF`zNihdATiJYq?-H?j*Co$W2Khx3Nff?F1}S@VEq*SDBcOh;5b*YR#d=MrI|1k z`3xg+3L?lrn}-^rb>Vb$Bci~nVQa7oM0va-r6cMy?Z{rLX#iE*mrl~Yqz`Hz(wnsN z=*HS|G^@#=zH3%f`I<=-p3J1TCGcn?e(y4=7ECFne{03}EjuHeDm;l@4Xv z>5A!e?HO97O{V8)j!_5IHL35a^JI*w2H9Epk~qOsBLsRi-ja4=AE_DG5embG0nI&z znu@+BQ_#)iE94H@8;PQf$YiQK5}?{5Pw8>URAw2{R(T6qrAk2y)CbXa+5mb-*9TJ> zu47${)$sJFTev-1L&V1}AS%W=iNyFOB$F_nEKS%;E=&APzDul4MG}WnsYzX^T1geC z@=2e_+{EEz-^3^~Jt2oU9KW3yAJ?2nj0I)I(H-y)Q5Uc)Mg=z7umuh1qS3qBImk&3 ziCj=e;9QjpZlN;6SCu4ES*b+Q83+++1aN=d@M)TbSI}*cHS{{<3VjQ?L6acQ*auxq z&qE3N3i_DJM^92E=m07U1xhoznk+*TNduNiRKund4)i`g618Aokp|dW4vUG zx}aad?9PZf(IH^scMBbkInm=7h2eNb>?+p(2Qa)}q%H&Vn%dN@9tG2@78JF!JQ zfvf~L61?sQb=dF^;L}!MlA~WUtz+sbSH`O+98O*ebslXhIE}@4-Z=u^n52EWuccp7Ycc9av+tS^^ z@$TsH^uN(7Xjk+Ox*zaHJdAlsi!nbzZ{b6_PV73mUhD!Ij-5syj)|wyn0-|1Xn~v( zwSrt_tU%5&Y#=7;Z{Y)VM!b%8JJwxeMIWjsphmTfOi}GaFjaHJszeZvl7*|PQjoW* z<;Wj(DN;i_7){sZq8h_W?3J-6{wlf=@itaNZjH|&TPAL&bjeEkbGdzVY|02GszREw za>YwZRjNrjGL=$INKH_6NX1kaDrP88R2Z+ElJbk8%C}&SCSRnJlET!agdx<@I1{-h zW+r(xs)(=}Mi46feY~004){tA5jY>7LOysVBy26b87zT|6^WYCs6Le>! zC*DUMK_)^~XhQLn5f!afkKq&QuE=RkK2le^1U;hV(Z;&A*gM@nm>2Z!ebZgWwt~LJ zs=BY(YpoL-r$uouV1!TC*syQvFIcqtG1gl(1KX}NVCR_M=q7ptx`OJ29wwWipNLd6 zmJpGCfNKB<(8wM145C6?BNLHa*b2N-yWwkKYPS|{4flcxFqiuZ(o@eBec>I7mhdnI z1^O0lC|W2cDsV*yg#gu46hL)A=BB=4EjV5ZwN;#ehA6V3iHaO(y5a`ZTd@w(D_TLB zP>H-3+AdE6zvU5-E7A)35z#=OBPH^=$OXAhq>DU4`WR^o@~3r$GHFBjnzS&y4fG^W zmQ3O1(!MY*g+nLAa1ar91tthe|4T5VB*K{>+j!CYB3Q+HB>2X2Em+^PA-KmK9sCVu zoD|44t#p3&Pjnvf?{}{Azj1E#zj6-t?{=C%Mt&JT#KCj(?TxwXwlVB~*4e(vmW|%u zrW2mSW$WDAOINshl@vJ9;%?3_g{vJK3;wnD%a67X$=hmMn+w^3Ia{sIa{5`1=hU!1 z&WW?u%xz))FL#M`PoB;CD*vvnS>a}TX3;Rmo|1o@yULEao|tdB1?vk>2ge)l4c9kc zL$85LXJ_&^`L+ICfhqwl*oU z2uOT5Nm?2HDkO)yhx0;_;OfxJK;uw`zkDdsA0L{|r-dZYeV)q=3!UWdhqiK1_!-wI zTnM_Hlzd%b0G}Zo;8%(qUtU`3KLp@1QIXSu$q`*}Mx;$}W~5GVLj(;jjC=|7h^z}V zi;N6tK>qTER68(By5jFDP4P=&eg75l3qMjE20X6cxhFz*ZnuDNg9MgsF6g*EfQ3F) zxXrB+I`F3i6JH=K@YfPGfwAJXz;>}g@VR&`Xc8NQlBMF%M(Hn@DOV5|gMP!zNIFRL zb(BeYzRX4H$psOhHbk~Yx<&qzY~Vj|j#Mh-iny>rG=$rTtwOhjsljH#{D3RG-@h)L z%U1_kcm!y!??UC-MSx4166)f86l~yW7Yu<+)N+tTm+a%f-0nJwx+BbJtV(oGk<>nvM+=WN^A1CI6FNY@CymZyrJ@N;&kkPq z?*ojtHsNhSkaG(S5q^jM0*c!xabftaxFsAT4Gy=E#878xQ)rq*hqg$EgWDuDxJGIm z7%ols*Ou<^cIXP9jCrMi>G!`XcNml!g3}OB7Ay>d?K&55PLT zA@R~)@tJf}*eO*N7D>Ou-9RR~qSO=oryyac_#ku;%tObD14C8BQ1F}3C%8s99H=8C z1zv?$`n!i$@z&6OZb!((szbc5PwutB$zqUtgoE_md*;jC59Rj!Ad6^Hp?)mR|J_RoOJ_YY{?vUHxL|7F% zDW-^(B6B0@@;vA=lnQqM+SUPujA-E;^d``?1|o@s9&JZ{Mw?MnF*8+wb)o}UYdRCl zqV8cmsQ-a{atkbjC`LJaF**iML|=kC@p#Y&`WW4W>_^8T%hB;je{=;>2|bGRKtChz zP~e2ZW}_xf%EpIL)xZpY9)Zv= ziT1QeoTDKUVnRe5gOaffL?$yHBAzKAG|VHyPah(3=xszHJ)QVM*CKY%HheXG8NW|Y z!N1cn_$~S#b`p4=%V-bUn)w$U$LvNIF+I?Ij2bLEvXQxq>}19u>zOdzia76oc{JW$u7X{SWFfz#7BDW&fJTb{MRo{ADKp$p z7#4PgUWDKf9qJt172FYM94zyH2~6-$3>5NIpbvk~U(Aj6ujS(XwKW%&*4 z4ZasUok!U={A?e>|McGBs(VLqO*}YP)%}od;F`p?b?VrDj_qqYh>kltxMSQ5Wp09^>hcCmbV=viGvpMz-TosV;lGvwh`)|8ea@ z>jJ0331L~7FE)|BMA}5Oie_>e(hW+%HYlQqA21Bc=iky`-=JKC%~p-ZXR4LNXw6{) zltq!4wh?(ngOKYq*?#|>R7A6iI;Po4MQeIfNotb%qI^T{W>%8x=)U9? zsw=6YI*>caO5h`zbP_{JFOg2hk=Mvx73QO##_YybhA;fPwg+Rf5dze0ggXVS|XJP^0T*7LD-r-`}jGdq_W0UE* z7)Hlpm8s2W5s`yj#Ty~Nu;1`R>@D0F`w7cvF}wu)y)Q)wxFW1n6hSzYEmx7vk(CiF z@>6Om)t07<|B35`1>y$abJ-r+CtM2-5MBqOguDK8;lq6E@OjP~`p7O1{qiY8h2D%{ zHSc2Jg-QzA+$Di^?(blx_isSyo)n`U0fum$$z0P3a7$=tcEwBdgL^A6B&=w=zF|7T8M8$&*7)guJ}H{99f5o*idv8 zRtKfAhUf>h89EJ(AR_Vr$w2NQ=MX2d5UGU@My8HhiFW8Av%%Oh*)q&wi2K5N5ozH9PtV~#u2}W`2<9s zAexi+h(_dY!a}4HtBK2a5Kq7d0qyP;WCresQu_fN{{-;E=Wc4 z5bVa|;B0J(;vV`IYK63eB*jZvgzCy43J~Wk3b| zd=6kL*-FJ**r`R8*sq{hWM<(V-`K*9zMF-sd{ISve7lR@`NkDTvlB`NvKvdUu;#L= zTwn7c;Jq;L2W+4DHI8fkrLGm=z3v+vjeLRndBHEBUi9@7{EFv$H25Jdamug2(q)_G<rR!>Vkgz=TG(0>w zIQ&ll_*MP8Lq0wsG?RZ8Oym0n(>YV%5j!F91!V3%cnA0$o}YYWPjf!n{e;VN>bS>_ z9_&{8S6_QucVD4pt9P=w%oA;zt%-yeKyL)NLH~0CHzMg)i zUp@WGdU=cU*NF>_WK%x%vE|g5oD%D2(zS95qIR8q6ah- zou)X8kB3*1osc|AM9S!8=zq*dbfprRY%{ z!w>|>4QMobh$@;)B2kk}vg%gkS#=k(oO%d(NHvzMs9H#-E4Pr}nMEYU3?(;%-p=xL zMRGkACOGmIv5uTegovTU2BIy|m8eN15k?}2yYOGQ70<#gcvIpUo|G=uSZ<$r0#<6qE*u zjRZ!Jg4e+Qd28?x&x7vY8-Y2#x`8pC=6=7^$&IrgV{T-_kHOg?|Y!D zgo@jErx(}s78bcZHHuDp`W24#tSd*qWzYheNO;ka6VhGX> z6&qmCNC_W;mckTt z5?(34gOg-4?2HI77eSDwfSCAN&O>HHQ_v)Zh?Xk;hvmX0m>X${`@n?f2&N`-u!e*h zZ%&K>*N1c*CwAlc_%g8C;oosPwh6z4wZ(^F2!0t5a^4}UutcN+wgPxUj)26+S!f{Y zlnv-w*@Fy`%aCz0itd(sp#-!5&4tdR8HzM8Ki-YiL$a_wXb(IZ&&HF;S%jNvO5Ei=)@6m&I7rHDgC<{=^n)w#E(D){eJo z|HjYM%}jWv`#Z7Y9J zSH40EeE|3YT$K(OUR3U5JXy8GxVw7ysNOZjD6;miXm#C{F-i41#X1{Qj7x8HKTg-A zYJB&m*W#Bq(S|h+7MUiVQn1Q_{+wdO{>scAMotz<7!(B z=BlKjQ`Not^Hs*{Bb5i~$5rmFm(nWeKc;2sR;HcPQEB^ihb#RLWYl-)-lVS9#iq{E zRRJveW)%+T2Bb{X4KCk8H@IA!u5EF#opgD_V0wn3G7T9~`o1xbnjV!w)sD^t z9iShnr!l9f)v?E@`f>S`D=wM7AK#2_mQbJGnqZ`LiCX$cVqJQ1(qQ^?(m%8*X&`+u zDUDVnm8aV#lJvZU461YdaY~4tL$NW@lriQ#*(&-7xjAYxSuScL$r-1Uw~f8YS;o=i zN#h!_UDOHE5dDt)9!*faW4cjaV^&i0V=qu|V$V@`Vy9A9V=Gg8Vt#;>F2yPtj-y4oUC3tb2Dqo@n!=z4Az0-QXteUBY-Wbb-Iz); z#QcghW7bBlF^3}4lz$?VR6?Ywx}p3_-CZ7~QOch*rpPQUA#c`=k+bv~DAkw+EsGkb zI2`?6(IJM0x5vc7n_~3v_?RDx<}qUxC!!M-3!}_XE8`ppGnC0MbUoy)+OrW{lNgCp zEtHxw$Hit8EdIqe3y0B?@G-b`cs_J6lo}}xl49pzlkkJU_FziD?BC+=&$GOhUBw^u zRpkeI-*YuQE4a??&fE@H0vC4H=~Pvm$T%Js1wWJg)2vx7mm#|U%2Z-l8W;6lCf%HVvPTfE=%r|7TyRbeOhk%F(T z)A=J@*1W&Yo_Xz@nYrH_H*-%r+_?)JDS2%j4fEPLZs$#M9LQhom{oAb(W&r{qf1em zvr+Lur&tWTZk7yj^(+10LdyEMv&-JQpP0IMcA39>x>!1TKUr3LeU_u%r2^OlwOEi!fT{WcBr^)$EjT{D;SfsllEmgSB2qvgE!hh?evvZaf6lBK5CXpuc{ z%=bP0%qu-tO+!4frpBHJfNj~iEaZM(8gZ{LE$2xu9qf5f`q%@NRrJm(8{y^4c6;xd zyxv{rslJ_-0-wn`hn;8d&Luj#^Db94|1D3Ef3$B|pc0oHe8roCUjOXSt-w^!i`g^u zD7Y*1GDL)bhL49=3q6JV!U^FYVSunE{5c#6whQ+UY!6-K-v+<3)q?N5j{~?Kghg?Z&QZzElZYg1B)W;sDgBMQeI8=e$GALknGyN)W83E6aQ@W_WnJ= z`!K7Pw^x?VOMyr3*GO;qtYzNCSu4G7vKD)Z-%Gs{e=qdD1uOB-Veg7RH@$cNTm_H! zy~%(6=e_kC@p4(KJRP&@cxq%Nc-m+6^dx8P^O%2K^_==O#>4)+?Kb_8T;lfyuEpOK zu5#ZmJM%L)IEyo9IV*qf>RkN2we!XI{m%A3>bOS!Jm-4+3v++TI_CcPyPBuq&tlKT zzkfZ=vfFrbvfF#d=T!B&bH;fuIT} zii*St_yCa$+lUD4B6xTc==%MGFNR%MD*PKYz;BTP#XESB;*p|};xrV34#{Vry}(1a zPhvqY^+0)zP#l57Ya^$F9*~KfAZ7aNOTGL9B_}^s8qPP8u5zph?nK3NY^FGattQQ9 zKSxG_F2LZ$1&g$ zxGdCgT@wDd@`Ri2G_ksOrkLmRh@H9f(j~rWq(b0Kq<=6;jtyOw_l9DjNN6N9DSQA* z4;Mhk!z~s5@OH&P;hG{bsP*rFYbRInSKgAp99$Z!7MJ|KMWfd4Ais1v~Eufj+f~F_maX>?yi?d;oNz^kT9TPBV%`3*%4VnO6yBrcXkc z$%+p$qvEeJ_u^_Ze_~J4uVbpvo1;Ha{i6m^r11lJMBfYOR5rq_*+FbjwX!A)*+lTC|$si7?dl41X*?5*}K7L$P8{e!7V7FBdFhYF_8=!uReN@}9bd3(5 zteuHh(|y7{Ivzi*cj7G!`S?+T0|%W6#9V_0>@Q_}h~YOLXV`<6>C^Bn`YV`E*A1Jf zv!Pz?EOe|EMc-@gAoDbXkX9NB395g=Me56NwB`ytUy}((X@hV;TMNn2%}4U|pOAsZ zL1=?$2$N#2V%y^;;&l>Ih=N3xSe0xiTa|x9Wv9%g>58?OwA4(dYo!6onrQ)LN!m`; z%*t-n%gSxk!O9EOxs~^*r&YeE=F={zd!@})*Q_*3T~M*5dVhr?l`dtms(!g>RiC80 zAhX;-nHGPF*$M#F&!bn;4r4WXoFR)+>eo_P+El7c^NaMVACjf2Q)E@ueDaKPJZV(U zBwsS)$kWV3avgJqJjN7}PDUUbD$7x`m4m4B%I(x&Wj+;BHl6^~2Ai<8a805%a+`dL{GxEQEnOeoPM1SlFZPcuT?eifbtDCSUDZL%+v*0 zc?RR?60{@p4b5W0=xSwCpluGt>Z&JU#p;#V3QaoJN4piPuA7S8(~ZPv{Y-3@ek7Kq zkHvI`T-0dDLIr&$`c}UW-JtJ*_RyCHehC-SU-tmHs(phj*CwJTwNugc+WBZm(-Q5V z`GQ^mp2r)LQ}6_`2Tqd1@DIdc{4DVu|49_$2x-BUV5O2D@D5}; zK8+lYZy^Wc^T>{PGg1RyW5TKuH?XyMC(MbN&_>v1bPkv`o&yf~4EPJ|R?LDE6*Sxx znxObc{teBDY=UM=Drm2GM1CuPYl-kYk{wQov<<(KUWUd4-~Dz-Z>5$t+*zSQzXfl;#On~)IUN)#nLZ%gLD8S!6(Y4A{Ut= z4vN6QCwE`CBdrFc<3U1O2^Es1W8t84o5X%$_T zm;`#oj23`(i1TC_E^A-?p^5?cV0tHhb|Uw(&6B&?HZ5FKT~M6A1VIrI9vMN zx!-izHPBMU{nk3iJ>6dHe&f9EIpi^UkFf*Teg4y2wNM7%Q+V!INm~K~B2$7L4 z{5aGaVnh7^jd~)~A-n|Y6z&U64(H2z!t><&VU1iEo)<|JEYdLHm^4GEA&nH)h@*r| zaDSg7v=-)u8wvM9)dY7iPG}WW2@3;(@IAjHJl<~$*8o}0)BMM9B3~NLg4TQ%nU*_OarBKDW5i z_g3ub+af0W28bD6jX22rP=LMjgm<3C!ck9Ncq{0nn(3(*uHcbEzugx?yWN9BJ={^D z%I;@D#=Rhz?W!Am4KiXcU26h|U8@8AL2fM8H7Ve6HVs^JhW&$`|M}ZH5BOI(=lS0` zNBb?#rv67x2J|jC`9luCIZ|lOI-e(1h6Bb;IX=09f7@~^hP_Adg*uk2s_Egg^jyBv0ZsiSFNm~(32 zlXF|3n`=MFF&+!FbAJh(0-eGMp5)*`Po1F7TR%9)TPrxz+cmfcw>(g#x zK2o)h8Lp}ntyLvQZr?E&k$w#&+ET-m(c z`H{cuJjGXW_TiU0)cg;-iECy*%Wb!{UVS%+8J|_CgT#B!nj+^-1t~! zS$s#OGGT#|jX$ll#6M8x#Q#z5i}xtY$LA_n#{E#4}uET6l`{)+xbox5DzvqDKC~!L}N{G6?z5e@pTY8P^9YuEpjT<0lFy9mQ&@8kqeQtpcewr$R)j4 zO*$mJ7n=x6#JAx(VwLcJLf23`p>gn7m=5HHO8G{iAKaec4ZzLZ>Dv%E=4~E$=wbZ< zcZPqh`+`5py~V%ZHQiss)zkkPTqBk{Px;3ptpQw|6`m^9 zl^#Z(10t0cHYggR(Qq4_LW&6z@UN60d-w~h%Pax@(dNW@rHzo4oyo4MjpPzlA$eNW zm^!2CORZG(rdp{cQDw@x)P7|*YKRi1g3Lv7B-4j{NyFp-`aTh&RuD(2?nGCL!zJ<% zex00zk0e{+<;egB1C|v}Jirv>7pwxAfz=_uVyPs88^KQANKVJQkPq;6Bu=a%n-Yt` zzW*?}g?L2nA>NY13-Xe~SOd3Xr>h^c@+9F2ZP z4`!JY=aI1LC^<=$L4Hvc zlU>wS(yVrq%QP&>X^KD(K^D0|`L;2aBM1B~^ z1UB(#dD5fg=egf=%Ur{`WzH;iykk6D$6kxA382UQty*@hCCAs-ywumx>M=S8bbH-3RwavK zW>c25QR8Z`)&p z?^C@?Zld}(ah`Hw{AGrY{YIBXNfcxpNKMecBvD-|`9kxM_yqiqebj3SM16p;s2&o{ z)!&Hs>IURijhXza-A2vPr_s%fAL*LWLl`R7#~h5irnJV_Q+-Pqt!k1uNwp}kx9V_W zf~phfCK#JwR4U_>ndY%dIw$HmsWCJriZs`;UP=zxNGjlcXlG1>oG zw`E_kirE*fjdFfj`{d|saXCiY_H2U<&8}jb@wdKh%b&is6TfHMUS&-KdBXX&IX}19 zYX2Bydzp#Y`hWXljsN<{>im4hYW;M_TItgpYr~IsthGPvwoZLN#=7HOigm}^GD}&; zP0OK-ZI*c%Q!O(xI$17c^sx+hJJT}q-73qA_xY9^A0JvHpI_Uie*0_x@;%$(`nk+$ z%lhi9{I`qiSx$=keSTL@li~;7*JTUYnbvl^#`(=Z(9=G+g1rQ0_gUedA*=91fTgYx z0+2+dNM*Q4{)_B^4q( z@r{}^{E(&~OEh=z!P+RErU@I+_@%izYhiIucslP6E~4CK`a%T~|gl z(bXm^>jse)?Q(LVc0ah6+)P&0rjyy4KV)-F1<>W%m1?H$L%jyqma3|r)LdnI>VHgg z>Ns7AGEq)4ih4oDkVnWW#7wd~-kDsE=}8Cro;Ze{C#Ivv36RGjI-z5Tu4reX30jWm zg9>;C>c*#IVLS?tC*I+$iCM%5!bol+K9dE+RH`Kjx=cxM=Rlrd5-684of@hp>7$xO z^j7Uxx~?vsIjNh>2)e7x0KJLXqE{-n>#HeG=*KJF`a8;bhKRC`v6m_;>Wa!7m8L!! z{hxYc%y`Y!SW)vW?y~lM{BYfw1igNE;zzwNagbp}(h~!oT*bIKd6BU+d6N+;cgQFw zKR2S~z8WLRSw?Gef$?$j7vqTJ2gaD>ea1S;^^9GUUmGeV?=o~t9&gA=ZedtmZm3~G z`TrR%rCc*)RVX%mtEe`Tm8u(eq|F3<_F2ZU)#gRLs?jgHYV8IwYeD|~zxq#N^BZoD zD{5RL{!7z$@pGGxPT1CBVS>=YkdWHa5r4g9EWbwGzI>Yc-*Q(~`f`I+bCRP~=aZf(cO}kI&P%AH937v_&~Xcxg)v!lQIwAU z$9RnzWOz<()&ttGj-tu{l)6)tKjj5xp*PytJ!31g2zQg) zudSVix6*FGS8Dg-ux=l|R+oW4(^Vwwy52+weKlf_-in_9nW}mEjd*4KKrq*LV$XGx zv6?y#9ibhM-qf5x1T_oCtB1qwRR1dGDl01*RBEJNXvP$e(F@gr&L2 zY(|PiE5*oTWt_ZUHCW!FJ}ZyZ=%A6>P0(Fk2^^ zN)Hl~$g@HjmK9!&oDKP*{=spPo`D!~4vu_cZpUt1BDls?V--YFOFv!MDq?)>qB3%vWGv<2z>W1!iHW?|-(}UW0AD zcbB!FH`hXWV=UV|iRL;UM;YRAm!5SyN|M}*i?6t}MJcY|1zVgW^HZE?-W^9&ZUu)i z=dC?9`@Vg_->dfUpKbQ5eg3;dWaiV(!v)iv{R+#R6^ll>@Z$5X9mOWs^Wu2-`{D%mmSUA# zQC!JAtEiv5sBpZySK(autAdB_2?YUn%L270p`f=%%zxq`3u3+93nqKt75wX6P*}~^ zxagiwE~>)5FFwKkTav^bE1k_HmR;kvmF046OeW4`%I7+n?{b68OF)n4aL!;(;^NI2 z>?cz?JKWTpjWW4?U&?O!)|O564JwQFH7N6X$+A+fSX$_`zN}#1`6HHgR8v7!C3Y>*vAYDANKR%sNhbaZAcR8 zhx>^_I9)s`JP~oxE>;l(qE>t^o)*T6KLCsGZD=*%LZyHl%DV71K09=eZ4Erhvw|Po zrvi(e9)D+hjK8+E2j9VbmOEBPb9m_+c2DtHwtrDi)>tU{y!r2ZmGbxc_T{bf8S^gq z?&eCqW4R~Tk-3{#F=r6_Ij0vJle?4soh!2&^Hy^&^1|GeyePhJ-V5$dZX?c? zvxnugan_i9$G7TlAD{itCvUYs)4WrEm-D{JI`65O73WF+_1sps9@8z9$zXu)W?+!=$58S!^XMN``kjG!0B{^68?&~`H=b|g)Z+-XG z>_6^NIWqyzM&W&*d)fOkZe`$?iOlc?(DtQ_xU-~m}q7)ByEUOo+Z(1H)V9p6#?xY zb6V`iu9Cike#pAPFY>oA2knxI0T28aX#Ki{EJUZHmWD;11JV7j|4JpI^L=WNtR6z8?S`*zd7yb-wg6ol1*jVHc8Uxx3(a3Cc64>{? zLk44fREs5}OYuw;B3h!42qn6htU+w#Gh{LUIMNHOsYihB#2HZok}R2mew7B$UGnqT zCglYDMno&(MWl*69Bm>8#NOrqjN2lJOc*bmm57O!Cmj&gC$Yq(Nh8IVl6H#6CM_0M zB&LcZ5^F^X3A;pPaj+;lcB8OEG%fgFtzLiYie;A~<9avHb8ZSh^O2I~SJ#gy=6EFS)irNIU)z*FF5z!hNO?Z<`S47ol0 z86O6}!w0~x@oe}Oo(!@8V!*$Qgi{~D-39N;p$Hz-fqxXr<<~%{ z;2rdnzYUV|7eRx`0nlqg3AHD}oFY8TIfutVhw)+1D||N;#C6aPq6K#~xs=-*%f=!C`F6xDzmI%TTtPM~k0FTa7&2P51zD(CjGR>s zLdb|%WJE+`WNbuFq-#WXq((I!nWLJ5#H*Sk`AP+{M%fdYuDpm`Q96Okya#$rRf;x> z*oxUA67d@KS6m*oh?pPUm;4Yjn%^?6o8UL_bstLTvzoGHDNX&-YfZ|f=EkR`%Eo=9lFUz%tr^LZYiY~G`jqz~ zQF6M-op4I{B#tZG88cC^FX{sSgqp=aqB==7DALJw@}mSMizRX;-|?_`2R>9h5`Q9U zjkggc;btL?1%z)ftMD4OL3j{L686IgA%p4!h3FZ<6||LL6gYQcqbTUj%_X-Y_dplt z9o`WJWC-3!^cS}Qc0qrF#4QXs{7*Q4u)DCYvyOrJo|{&OH&VTr1)<~g?x2)D5comW z0^ag%e|u`Y-y5>{c+^Xun7RzEH@^PV6#q#oJHV!!2XE1>LPHrY^^Q44bqRN&?*ltK zo0Z9oWF27c0S76}E)FkbPh;^oaqQC^3CG8Qpm?Yp8V214PKq_W9Z)M+3mM=c+qyB?dxEydWfLN@OGaXtbEfiFJT^>@M&Ze)4tfE|QMsk^`gW6SLGs_&HTH@CWq5?gI~d zFPR=Gm#jqwiQ^F=*azka*MKZTHe3L5EXn-yyz}HVULrY=_krlb+YVmuOyUQ35~1aG z1h2ae_i)$XHt>JK=2c-bZ+K=>}*Ih;iuVm<|{=wktbKI?BuZSrjlt?+t-7d;DuE_YqvocoW!pKflz?7HNi z>FNsBIYD2PtI&7Zl@GW{a=*vD+<(*a#NWm1_V4kw3Owv8a%s{_@>Ak`vLpc~kH_yK!m*Wj_n0XB&!|P%Y;_sBTGa)uP#i)=%JuLa>7U@f zl>!%vYIxs;J9*y)&3U)@TJCQ01ou5Lg*%#P33$;Y_bOfs&Bi}LUGOp}26*SHvA0kU zY%(+ug`xGxYfcN~Iwuiy|0vkSxdgxEl<>NNe%w5E8K)$ctU)LWB17Lf5RH+x;*O-o(4$?H6B z-0kdX9OVoeS~*`B;+?Av3TJbJ(IEyM#x4ep~@s2{yQfZQEXb+L~D1*?L7QwYJnMt*$Di716e}j@B-< ze$!sE4yx8zA5=%%@S3r@&)Of?SJ?ga@s2jS zQI7e#`Hm;L;|@_nu46?5>9jYDckb4oab_FdgKTZc`M0sR>p##4-1IX& zLmZVJo~w`dsoU+n?#=UQ{MY=U;Nw6?&hB6@og>9N{|XfUp?qA$$%^6^w$S`SqM{#CFbhd<$S5O6iTWWVKZ zV=JL__EPq4)`xI?IGX7izDI3hmWHb7Az+p;K47GF`E zhk)6Mk_I|b_dpMsAKXO^4nC%i2P?p(09lzV+7yt}Lj#|{dubJQ+}DWe>3tgd>W&Ph zxt0a{I6eiY*xdeumL&gE(_r7oI?TPI#^;=;Ep?pM{IvTj3T-{gS+<|0 z!>!!XXO@j6EiA_3r{*Qalg*uryPG=}cQr369%{}nUTz*#vdx@da?RYVRAlK>y2>)8 z^poXPX{xnj*;?!6vUgTNdAe;?`F7i#@(;GdoCNI3QJ%l+dEWKlT)&xt@O?2}^tCZ3`j1-n_&K(OKp*>;z;s7;a5Ui1djNla zk;@U1xW`kcK-SgjZVj@pcWJ4&8$)^DGFIQjFrcooa=?0DMOCp;#>i>LazT$cA?_lc z7*0pC5e%1 z39BRz6YfX`fa`1g7)e!Jk@!UHRPn+XohT}LnrL>UU-&g*y)aUx6J#km3NFZ2@gt=9 zWN+~-^0Sabz7w1xZt%hBJGmV1PCUU{;zO||m=MdxFzh5Y5mVuZvCjBz%zzEY24Hv4 z^?-qT3CTtr@G7`9{12}WPsN)8h)px0g-`}(4d?*QWy`}0KoD_S*caq71^)BYbnnCv z0#>jxf*elT6v?(yn^ej+hDi4e^6Tx@p;lX8=9l=QJjo=>ZkKklmFu2M-CG^a} zp;o!hQcFDj>1jR%Gb8Yg84}tFSfzVe2f}CAm0+zgfcpT#5fk@576T6k?Ehrp1(YpO z;Dxdr;<|D-nWKKk_eA9iCd9rF?uaAN!ufix~%@Ga&ue`fR) z-~z29TSOit$Eg1#e@1jAH$^ldn?!UbX;l^}jc7zRj~GM_h&V}3iFi+@MZ6=gf%RV} zRS(jpWRcgDJaU;5CF7O<5mOZ%h!*m7_#x?TFe93c&J;!?$^3h~%Xk|u4=v(6=iOr$ zL+@Fy*;KfF7!E(8cF~=Ky3kGEso)6D#=s8ODu0Iaqc6%a$~WGw^S-zJ;T72OJxXhq zr={hW`-6F>`=z<9yVzXe(wc9&UYL)$R+%@rGR&J?4^3BHDW+Ukv9Z>5+Guly4Qh9H zLl1YAzN34OzPFocIOkpm{H~)L2+#i-ntJ9o?Dga{fcZ+p0PntrL*DrfdhgVREZ@q8 zslJU3Q+%5nmiTryy!G8_XzJ(aH~Lfb`~4*i{rou%Uwkgzd|$b4v2RhsE8oBR@%~=M zo`C{WdT_Eu7es7VL;u*vP&v*9s+)T=-NoCSY2wcVPM9U&^>$!|nI?c`oWu!04Cfr^ zN+)BJc;AQ{@Bx7a$r7uuf2FN(m7*OnSJjO?2i)v?qs9xeVpnfjNyt_M-LHBj=CtA z5*aI)uYSfq95Ib=R8^DRRO844%2s4AWh^;R`HRR@-XkDo0U=dZ0H;J9(N)PNM=No1 zxl%>WR5m7g%68;2MGvySBANUwFC~Jq14Npv4d_x`$LET9_-A2HtgB!yI+whN%)vn` z04?Hmfsb*oLW3YVTfw=@d|~yY7KB5AY{u$>V*sacrzh4l1Mta{JWq^qo;+iFPjAy^&s7uV{bZW# z-D(=_J!Wk1v@lHd+-eB9V|3TuFY9vLf7Nz$53cFtZdX0ry-mB?-9mfIE!E;4p?0gM zt=8#zs9ob-QO)=Ds9El_)mVLZYUlg!)K&PO*3S-{)%gM|8b$>d>z@SwXNU;3F-{AK zOjkoeQ+4RLxfMm5PgCnHpQ#vY1!c1)(mLB-`l(&W>~^eXb~~>y8(ekFT=%^2Ru7l; z-FuwX-#?Ho2|}Dy>IpC#od=GHTio5yLtZ~Xm&Py_Y9?A@lwclCiO&$PW&eF`F*;#Q>^RYo__w00ge-Ak!fJ7g#0}z>iQB~9gz@4P36$to{3X%rxW=M$ zU{8<6SOwWpM+M*1Ed*;K&hSZfI6FezGtd`uxY4H^NnK%|d zCN^PP#c!~q;?vkW@o@~1?8in+Mq)c9N^A{q>2;P|MSWn_w@G{*IVBp3ECGDK9)daW zFY;d=htP9z4CBfX6cX`F>`R>QEN%E~xE(!^ITeKH4?a!E4IJS8oNEJDf$t^R0{I$@ zK963nb+>9Las3DKbK~l!J0oj9II?RJ9Ve?F*~_#$?QONg>@TX+_Ssb__Qh4%_RCeX z><_A5*soO)j-^#`4lcM3X_`5A_RU2l_6ySl z*Hpjt#?%V>j-nbo1cnM~>@@cE>NKhjG;7Wi}6$(qc%#c9L7&uzu=z%8N9SO)hZ z(Sz4tuoCVlzKo2PRiQb`cKC4hRlt2G_{ni;f+q>2kWR7--6^j`@6%?AXJv>a+Zt_? z#AQB|?9Z&1e9NRHM=~FP=i?-Y8mS~VGxmt5roR(Kq$xzzDRYENlg|r&CTjVO5>olM z;)arqV|NkC(k}ZQ% zWy$ab>33d0GM$$#spOs%_uw8BU4{Yz7@VaH;%p@*ve#gpSWZ|PPUqIrE7_N+&tO&g zJ~SAxf&%`@o;kkJPN!#!?FzV`4|G)-svLE?gZAXQ99wO5W2?0)(*kQom={+pGYu;L z$Cy~AFa}E&8<^r^JySGIpIYQ^s4l$MATIjRkW(bmUoC2=xD=N9)e zFh#!&!s4z*cJWGMZP9b%nm7|C7#y>*OO5jw%JMjHm%@#K)K-dJ8@yh9G9fjstwWOT>t{T4Ge3 zp2z|p+hfNNJz~>{YcaX_vY7Gs*q9dh^qArJvzW!W7;yI%$9}-YaUT3@Tr*-%{4!!z z!Y5*0VkUVbX(wq+{z39n75t>MKlt+Whx|L~v4V#5@q)MM6hAh744+OdCx4`@BCC^I zgMDO}h)!Hj?2X%q4~QnQixFLr1M+b^Ts#TNA$zl*B7?(G&@6frvoaJ4ybct58u>do zk9$8_Gd)91?_8dS{?3v*u0vf@VmnZE$=bg1vSnC#f%#=AVxCqqz_hyfk+BfW)cY3o zFmj8E4Ml~s4Vwz57?8rbhH(WW4ZrdS8b0I?F_h(J8&>4EH|)=AZ1^LW))T)E>qq=l z=*N7&)9}BqSq*zWKhqui_^0mK`!2dk@4WT9-&WS+Z#(I}ym_R1{sw9YzuDVheEXNa z*ZZA@TOVc`hkY7o8uTUGJmK3Y%Z(q)tbKm3x0UA|xA!mn=r~^d(fO|Qo{LxUz}-u8 z!jqz%=KWF~>)Ta()i<&}-cRf9`FHCh0!G8IfZVhqFyDM6Ahj9;cWqn2zJ?XTUBg2r z_otBA+mhl3wox5J$@CSP3)~w&88hcecpa~Z)f?5b#}J9oF2Q;3Eiuh|BTGYamF>{o z>R9Y&6p4Fdq(pjrEE$`a#{Vlx#~+d$C%Bg!C2%BX3CNUX0#(X(a4i#jOr8h2H(7#N zNl*Cki81_*@iR$Y+$Q3Wn7{GOQID|-^)qyKL=jS>6e3dh3AlV=CzZ$xo;(Q zZa0aC`$kN2uK-U_nRo^7yI9XVC+-0M5?_K7Bwdg`k}Jq035Cp-Y(-~+d;d^LCoCjB zi|rRXu})$R{z6oP*@f>gp71Kh@E3w!P8aMB0b$GVOU+B>^MOIyi-=gC+1xq&4yb6jPSMctq@i<7fn??7X71YCcdxQDt@ebBNjyPBr_w% zOIAiamh6p?N!jX2(nso>(mx_qGBWCdOdr)&u8O%WpBPKam&D~LX2yS0j7}hx%@YSG zEs1B8Z<9VKFDL(04o#_1eoF}{`=<(2xv8kCeVSdlIIT{3D(#)}OWFpdF>Qj9mp({2 zHa${VnO>n7mGMqdpYcucqEWTtOQv2?+*qsl-XyHZZ#qU9)%=$7aEn@{x>cs?ZtFd& zo^6AwkL@-^wC~`JxRTXY&Fb`*I=i!8J-Q1N>F*L$x9JK;Zs^L7%ax!H5oMjSBer#1qY8F7qRejpTd|{UgyO%}9p#pmGi8HYT$9!}3rhZMIz&?1 zc$K(g=1tMN47KQ1`X=GMG@fvE>c4{M6rtcyQW{^FxPeq9$jDRiEV5PnAo6S65wcm_ z0kTbOJJJz-h1d~=6Y9v>_^pUiY`AJR)=n8lTPSXz9@!vtk2D|2lm|Sf!AFoeCVCW4RC5kGVK! z7;ig=1$#JS;bu^8cp8)e?*_kFC!kfl<5D)bF~4Dy1jfO&W{HxZf)*r99TozOAlE_52Lgw9}%xTo<6+$F?JZW8b(J|YKk zWBGl#oA`b(AD9k(;ftWn{I{G&{B*#hy~k#VG3-9X8`e5p$U2WL3YVb8Omnm|vmg0I z6Ub5e0X%@-0~@Hv@JA{g`9^(3o>50o4RsJ}N&m!G(XB`eeU!h6Q3`#`bJ4zVqGS}S zpR|%SL)M5rL%xySPw|@#D^2XlN-cYuvVz@4`G#GnSj=v$NM<*c|7KN4`>;Aoo`?Ss zq2cKQKb=Tgs2f-W)gEaY`o@h2W^w%f&tZ@64lVRO38i?~1;%?MzAJ9F=c8+Yi*lZJ zY;$(D4|T4!&2S2Bo1A}Jmpk2-xy~5N0B4Rl%DKlRcHT3VI0A;1jy{Irj<@<=j&1s- zj%YpVoZ8UGxlCtv$UuL*YwaWZ;%cQmSoN>%r)IfrUu9bxQDL&4DqCP31~?^E#ceHJ zijJB8F8E<;n(s75=5;W3%H3}0@jG8X{MS6a;pY%N@vE)A&95|l>tF5l6Mt>gyMM(R z>VKCS67$9wm*ihDt|({)-0HabWZ^!uwJ^^tDw=O;QIu-!UUbgdq$u4sy6B7TUC}su zWU;`pu=uVcSRCX0T=LqPS9;E+DO>3NTuypsSM>F4s%Yd{T%mJoE6%vrSMG6>ni6-V zW`O5c)g8|PZLKGzy1_HM`io~u^>RBuW^)X%=aliDXRvv)H_6)F7iVwk&vZrw65SC&nU@F& zfYYuraD>_znnQ!p8?&7m#T*MCW#+PKnJl)Gaj<^?yYyKm!0yEyWarZg_Ck69D@2VB zx2L8uBSIqqH7boN3X}#Ffl+}O{!2cc&*NF{+w86f9)XVDGRI5LKKmNabX#{%V=Dkq znlP2o4| zt%7FO_4x-aL-X>@>fFxe)Zeh#^h;t+``yz#;rC|qw%dXCNUDH60Zb#sjP8;}F z*E4uk_cVB0=Lw$FNkWHoeM9$jt3u~=4?sh$lP)ZT_3)D(R$YN25f zHO+XRnq~S%eKyn7I_o@oiCs%CaQ0?~x?eJry%WQq{3)#X(05h`dIWm`NM9S-6`V2L ztFFJX}9k{PH^as~}b?x5c#@6i>KJhVvs z4LG&0p!LE*Xr3SsS;5anQpuyR2QT4m$C7z<$ZEh#`~fBLBEg(=H7Cr0ITqkXVzJu+ zF6|Z8=5Qz0R|W;i$WP(6%!V)zIMR;L!^5NLcHtGYk(o@NW$sdY7)NL-vn52+Oz$p+ zCMGz+m>+Z)js;g4)&za}ZNY8&zk&<&M}znEKY{{-EOg8;D%8`sHw2j;hwLUQ+qt(X8@G&p%o`nk0y|jGkkOnu z=s;*U>VRgWtGP4K#=PxlDy&BbB3rS&C>Q^Y^}#>j>+o^J75p7>36CO|;-kqZd>nZJ zYe}}nB1jwPC0|5YR3FW?VD=Lj~V6NP$otY|0pQk;#?kOuK+ z;8j;DHEi}DiMh4UW4Qhxdo zX?FTX>B@AubbR_#$$oC4tq-`=M6ZQ=|y+z4Ii!kSIw5yjuJTHi_=T%S4l4p(qpn3TD;k zg>K#e;LR=oee@ZEN*)T_==b^ac|-XTyfRYD?MhzbPA5ikC*cjyRBR(O4vmL0kXwMd z)RA+LTfy!ItzdHjwdo7^otqc7g2~QY&{mBIXHtv7j^G3RGPsuhGdO}CAB?1vgA~OL zmQbqTZmJ9DVBQHXq1J}}0(tyX)N%R?^@Ty{li}HPM-~X_u++>V_8i8-E@m!pBEwyv zW#RXbC%lzWxe1XVCTT`92mLJxdCVZQ&1t-f&Rmth;`z5v3I;Hcoy7-*bN^g zs^D)#I-)0zqTn0%yb$O06+Z&~>xZye_857oSb_ebvY~XuAZ%--9ur4D$2Bnr zh|;(fWM0BjeqqvT!H<-q!YygHM0mzo@v=sX!2Vn&ZPs{$bVcLm(shj=Nn17ED7~H8 zU21EjlQ=RKNq(nSi_fH~#c`>-6ni4jrD@v!%mg2j36K)mQlzas7X4dZg_g>PVN2z+ zudH8%NA^anF8g!-m0pGQR$qD?TTLn(h;=oFp8<P0B{4o~8^dLOGv66K(?Y7vmH>)kDWT`#4$$uKIA~vZIrKifA5a({K@^LED%dl*K8}vtAJ{u@^NhS+ z$T@f#HVLUFqS5IB51I$O3o+7Bcw6~nysuJCEQ(k`>Bwh!7_y)kWH}a<@-QdS39pyhwT+5%An9b)Ww&Kr9Q1Dm9UnR%IMUpA8e-V)} zY+`EkP5egGLHt4FS-ecW8E>X;g3pPl#xAPX0q&C))hha;(TbgF7i&!Y27J zc%^(TjL3JvCuIj=xoji6NZJm5Dq(mQ;0$dg{s{7|XLzN;HM}}O6W$O0f85LDAKayc zlsg>%2Wo}&g_Nj;lZ9;N?1k&uk9pnMRotI|me!T^8`>3CKyY{0J)43hP;KhONST*Ve?> z&A!EV-TuMHb@2SH9K-!1K^OD96?&O&(`*q@QLoDcXIsF**Hn=hKkI{?mbc#0Xw5LFa9OMMwlj2e!ui7vo4#<;Pj zu>yR3Y&(2c>_~id>@YkwR){CZoWbg%DD*&N0{S{)1ae+^41Okm!pj3}hj(I#+aPQT zbrvk-oFbpHxkP}q6YIqqkKPP#K}Ljs!tKH;*vrh~t!K)(Lgp~{0sWkNfS$!O(SO2w znNf&=u^?qkB>IM_MgCz{A`=)3TtJV2r_%YnrgSVXl@@bdl#R0l7+?G$I=m;;4A|>4 z!QI&z7#aB2cgR1|bHjJh`P^%^{qRh*ymLE@Z(TR^CC<${t7CgzBS%rq4*MU~<+d1Y zUt4C?SL-EB2WuNmjispahvk0dCCjJE)fTa4x#gHNjaPZx##GAfC7O5k>Z-$ze${=Q_iM_X;o9x4 z1@+C{KXupKzZx<;Z}qP{d4>e9#kjyLG5_*PE$O~$%UItd>ong=z}My3xBLFIulKzI zF4AbnQQsxUb>CoTnXjoU6EFbw`9a~@TcDw{1vPSp>!=EMhKWuoB?5ocaC)f zK{$Q!X;2>dl>3JefrH{Sq>-#G>XEm`ZYlGyjEF9Hcl9@16`4Yui)>5eMK&g0Mh5VK zk(cnl)g$qD;QhZ#)fQ{5+<{u<8f3ey2@);c0OyHc^EQeqxvhjME>Cb3GLl1}5+aZD z8PDbvWB1uotTB5A+Q9N5#jFaXiuD#rV4p)~u%7J&WX7VC{wfsUj z778&n>=}#^B%hkFgp4@+ADu)?=^H^?D9yh&nClr5SnulQk9CanRarNApPH|G)*GL@ z`|97g(sj3-th#j$d-VjnQajc*M)RljYsKG|J>@?0ma;+StEIUnsPviXWXV_4mXg<| z-zDEn(@P`G&CAZ4W6B#_q!p(v)(Wn5SLJ%E2{0{FH2rPeHD_%@HAdSA%}{$UO|5-` z=1<2dO}XQ-X1w#E#_TND0B&_vm8+rZtotAB3D4l_sou-gpS{J^8n3SUo%d%opbb>h z-u*QjeVc35{sncv{A24k2L|gD!K8-2gO3_`q5gVR2r(ptjvM-iVvO@bQq$4UX!DQI zGYd(LwjH5@_UZI-XCiaJt!3VOzlXj4kE}_d0yc{gKyO&t+-uNS-XVA$ybXJSoFEy% zt)7gxloS(1GML|88RRdFK!q0~6{6$O77-GATAUS^DwzwyM%Hr@8Ss0Vc%CL0VLu{PvJT^wQ3+pDEj3vnWV0F@t*exj= z>o0wTo|CLawc=)IiRd$uBOHhn@NdG6$#Px>$Y{w?n9GJ!p&!st&N}u0c7RD>ji-E! z8+bD}`W8~J+^He1vp%rjcF*6}a@jZEROW4G9OLb8;COrJUwE1}Ec3Jgtg`9#&)lN= z-|orv%{{1YjpvZ=l;@LfljoT(8|*1z&kWryccyNL+gjh*{k?vS+g`ukou&KY-mHrS zzOxOU(G3Pqbwda5B>f@pD?LEj7^e988XowD8Qi`F29^JkVYL6E;UE7YFnd2`XcAaq z_$$!N@H0RdI6=R@aqxqF7?{sp2zJ$rL-Y01L$&(*p>c)`s@!mgT4_w7o0{&^5$0jc zC`$uVYCRafU|+)e;+)EE?rF@q;?r?j1pk4`sBPSN;Tb$Pdn|m2I~?$3Gf_USM?aBw zu@S=6c)2)@m@4~C+*BMRzp8rii`D<}H%5&V{ETJ^@z`xbERGSLh#MjL9ydnxJZ_}u zK->gTr?_O%ve^ED1 zRI<)-d93lAh;TQSn8^Z}**;WDYHYA`XqSIz(C=LySmZh5cezS@ube%7Zyo=5!5!9< zYm4-dwg>Ko);(^sWr%yK1#fern>ebH2 zH7#9_YQwIrb+_H>dXZ;%{Sa_IvDdSxzQ)7W&Gb5TsXm21!r#?^1V$QP2ck_=gWF7S z$ZT33+HC$1>S~Fl+F0jMoo&ykEPE$7^9zWC1cOvZYuVc}{W$fnk z1kU*IVki%|!%lO5@pd3W8}qx*~2#=1pF z{9oeH30%pH#7&a4B(LO4QmiyJIZBErqtd%c|4Cw!MoXlLW#aGgEyerdHj0vCKMNN` zHwf-W;)0gyG5iwMBXTXsP>fP^B4)|=y@+^OO&p~egaO?D~Si)F8L1~AUTY# zlPm@21nW>rvJ&klZH;c0Rv{au`;e~ELC97~CbCRi4LW=M;bFqlJR851+nXf0)9?|{ zaC8?Z8s5+T7uv{*Wv>d)VwN+vLZfNBKZ;86>ViXDPXe3l$Ne>y9li~w`QA2$IUYg7 z8Fza9PuGE3pL0S@N9W|~LypN>n|*!Nczc7U*tS_S($-0nYlSsSz`cC5)mu5unxy$3 zaDb1u_R);63N(GJm?p{ERugBP0G=<>?6%I*{B6zF?6h*g_sp)mYCTm^XZ>F8wicH~ z*$PX0+r*_EZKq3m+2)lTwJj=9+FzD@ux~5f=-5`4<(yt_bdIiA?%G}nyMJoFySr*% zdhnXJUZn1$57yoH8yijpb{Vz=Wu~d2I&(|vj@3n3Yzyfk`&#;{V*x$a`I`QpYaFxR zEeRj;Xu=D;i&!e(W7bZemDSkag54@`oP8kJg_A+aAcn@d%~%P%Z=7-PUEVX~BiaIU z5vTEVAwok+SD07HRjCEz$$Y-zEP`f+YnB1H>)j7m5CkT_^NMpA|HT`p%!M=JF4z`jT%I z;|RYj6Q3{bfo+nMplu}gQMKeAnkznm4iT$?qiPxgi$23rz#Qu!_|2>3|H=CdGQ$V? z0d5bzm77ZfM+NznyB*{<$Ai4)4Rk#86aJf%%l*mD;rLiP!iC|BR1R}25TM3^TwV)T zzaY>4(SOxE#W&Va=jp1;c8{<9?!2Yl<&bD5+i#b5vOO00~qQjWt>deJeg40k># zTkVW5Pj%InUvr(UAl)r1_qqd>7WYd{f6tPtGS3KYwl}(ZKUf3se00rGAG^p~Yzla;&hSoMBlY1IG7V=?_wlXP7AHSM89l$ItTQa6h=$@fLalRgP&Bzgqx6FLj5aU1!c zVqcSJEJG}e=}kO~zKzF6$Kzk34q=O;gqSGm6#68xFFGw!fM!L0Lee8oAT{d4$U5~Z zq_w&)QWX&a`T|w(Xw?mPq;fo*sVLyRmJQ-{mp7tt3emm z+N0J++Q-(~D#&)FD%EzWD$aJfs-x|2)lA#Ps=sXIRnNh`!D5@KMeWbD8Frg?mOY?7 zV@IlQ+lAFH?P&FHyQDhL?$L4`8@1CNZ0&i+ld1y8kEmUgrAnKr`Jr23QVXmz$b zP+j1@R&&U6uy&AlT%F37Rqyc~*S+?y*Y6E{HEs?LwcHPNwoB-9u1(-x53y#4*0A;A zI*_-U%e{_*z$Tf16o{6fvjCIs3Gg>hS05)XL`@`*#MF`Q*lv7F+RRp01f4?L8pDIb*sqBKUQmw|b zBVOVu>ZU}O$O_^`)Gl&kOf&wRxZnIK3DX2=Nfm+*$!g*9)E>fK=@*6kMomR`Grx+; z8+Q>mZ;~Q@(s--ra^@)^(rAvrl!o#DmvVwQn%E3q7WV;lMRh~)h|9d7ObS?#n>nRq zJ!=s-W5GtK0p-rqg`<-Ei!4z5e^x*2a-Pj+kV>rIy6}&(`flYwVuVXlI|w zd#>}^2v2G4eD5b+nQyTnBT#6{3|3iu!F{%WL&f%4l*jR%igvjvk-Is4#k~Odqc+oX zJR50XRR+A);q*n%RQi=?C*8sOgr>YWqxCIj(13&aD|jkAotnsc#&lv&V)x_V+~rU{ z{F-aSBH%v!RmfYB1)U_z!BbUFiNZ)JKQ?xhAS+>-uyt}D(YaK?5c z0uf7yma0hNxZ)|^S>6suWk0bv=?TErxP|SJNbyR^L43KCO{B^O5%se9#98@nqOIa4 z@l0_aWb@t-+m$*ZU+E+Mr-~>0L>whcBf{jPh;p)A)rOp`JV4x*)A&%?6g*8Dz`lz$ z*kn;LnA6|H_JaO>6;Xf+@Zo4r^grYv+!?WR^WbC9Sok`}#nZ9h@&>Y>@v_-=-fwn) z_z~v>?1Aj?V%`FTh7-}Jz^n5Re}p|DJLCTfzTxLZIm9SQJ&_>WO14vUNJ{43^?_*zUe$b#c|CEzN|ih_Vs%O|qBeDmIx+pZ8qQ!ve#l6S zeB5Y4*kB@*X>EP zv1{+>wq37B1v~pAXLsrpc|Yq9wW0mg2&mn7RetL!%5^O}D;hUv%WpUNE)``SmfT8T zE?$?qO*AukuW(7?QNgkJ=ls{PR#Fi&fczfyg~*TWOxV>GxLkb|Zx=BfZ>zFm8Op0z z55-LEfV?RN4)w5|G8}VBy=Zr733>uJ+#$(Dw6iz?<%nh={RF4s?&L>aHm>7dL^<3J zNDGiS+|Ch$^*~RKmerH>DLj)o$>^xF^yQEqxZAo@djpq3Hv!AWg!{!DD;?#pt^^TQb)r+ zswCW)ZqDjYuVGE3FS0h!Usz9Ql3hv9VTb9T?Cy+=vzY10*}}}{Tw=Cxelce_CgvB% z2Mlf=K;Tc%7@D+ScSW3PNU*%`A1`GGGzKKjM zj${g3BCTO#vf&)P>;vb4JQm7P42Rw-&Ok+qYVcSA?Nhvil!`mhbopZFFPR!zAw9zB zDlxE2M8nvPg=bj{_!q<1iNBZ^*ckc^(u(@dYaJ?s5`qYa40LD30~28j-v_E2FsLo^ zm`e{W0eL>N5gS%*1i2rG6unpS*s ztgAqrMCB4^X=Rk_ho;&EX?MGKSEqSWYi*uSbw9libvJxm!v_B>Q}4htiz+zSULTBh zT?sw$tfvzF?Eo?LIbB9gU>*avO*X4r_#*opu#R}c7a=KY5I2tXo*T*f3JidgxL`65 zNyC#lYZw}el(@9OD)>{#Y2v*me*S{2^U<~g2b zCas%iZ0_!50LgZJs_S8c(b>D7}9S?g2#+uCXN%9=#rE2y&F)lRW30ltDH%}DEoid+j>KFso~)MNfyvcddk zG2d(}{9^iEu)uUHA2%(^t2J)QEj51q{mPi}`vSnp>^Hvqb=g?>tJaAAjx!DW-Pe@& zd!lJe?s`+VylPWs{vvaq0*84<;b_agqU)A(#TrXaNvyR;=@#qpvRbRNysIs<@}X^k zMq*!A)zjWcyWf6Y>$j__dpYJ+uX5b1e&YCE?R1!`5oeQ{PR_9ykpzBPtw-(2Hu|9R80fXO^4m~QPI8f?p=2HS;ndq*Xm;#|eBTvg02 z*VOPc*PHM;*Xr;nR}CX~?PA2Pd(0?Ta=6O1EWE&dH2lzgE&S2FJ?wN33}<<|hi`j^ zh5z)f4X^N7!v+3*tT}+oo=VZ|45opzo5esXNWnY6BjG9pLcow2fyifQK7Rl@|A29nJQ~fj*`|8tt8`!D$y5whcE$;5{$yu zlRMB?_zT2_y5Sh4Iqv;1**eF{~zHiepz_G|0}c8f0fzmf5H6lmoZHOR;F!07S{XQhX3+|y^8-av&=V} zIq7Z5Z1~IW!9z!yJeH7hcF+$(qai0M6WoK)sQd+@>gK zg@aYe6RbD33*Ulg69t5s=*{0w9u;WGO+tor3FG*QqCWglqEY-Mq7nSbqVD`wA{n0$ zeI~1fi^*fc=47_eNC<_i35!5MlnC5-BcT$5)8czHrzDXoY$_Sa1Pv*$}Bryfd zw<-<%?-3zE892X9k7*)qAD1Ed5wDXZC2o{XPRf+6OTI6gl~OO`rV{emsomsHQ+vtZ zq>}Raso!L-l>M^dV4pufd69Ht(j$o?(Jx*TPm4arI)yD_RKinH{RA%cQvUxUZjoXY zh^{Ky5?AF1@Uy@(a~Yh|=1HEQ!1{we6;}hU(l+FXs14Fvl!%yx3gi-C^luYhfJX|C zz_o%^a7RHu_%NRjbNQcn69G&7AYtO3#n*DDV+mXgIF|0iUpP&937q55I<}DWg*BMP zVvT16;e!;y_<~_7C*Tj|`vjpS-T}eEp3{L{!ZVTpOa^Wp(j_^CSRp`a83R7^A zs6Bp6)CW%$&%+Jk!+5zQ7cZA~C5*CLM4W;oPk{5)Az)n$Mb6{jjB@gK#jF#Yh?5Do zCp-`~PnsgSlH5oflUg9&p4M10KYat3zt>9C8JW`g8MCF2GWJQe83&}VGA>A4XWW#| zNS`ImNuwprQ};>4DQrnz(gN{dQ1LH`Um#i;H(SVx?IYM4-Iw1L@XVLtpRAKNgl@Q|6r$B}|hRUMEfkOWUK#RH#g}?yJBw!8Z5^xA( zMOPYTCuTF6H!Z-d#ROnSVOC=kFdCHcunw1pQRCRyb@-iFK4Ab(N?3${N4!VaM?$ZD z@5n6WC01OE%C*l72Lfm`WQedPRLI z>`rB%{KR#Feh^lm02|O+Q5%0a$Q1Md*9#)SF9J6BPXK`}=zLD8AdNCpkV96W^WI1J zr%81@BQb{eiYVlLBlhFHCsuK@(CCSfc!Is0U}avzPh_BS7Wg>sBW*D5FtrW48Jd9| z0sh9+lcO;b(gUD7ArZKQ+vD$y?u`!sINw9xNW|ma=RN3Y^2~8B^PF|To(5-`JJ5O4 zeb_P8Ep`OBU)qW8f%bA&t8KY!smr{y+jc`By87E@8PaVIJ)!& zcB@I^ID_W%&DN=|F#BZpAV-*IgtN#K>RRc2>{5CGcNEgw-4mJMo`|e;A4FLWw~#IF z>&Qm;4dkl(4wC79f@HYAq2A*fB-yP)L}*TQlRMH!@htHbdS3X-y+&UnYN|=}BYqYJ zovX*?pr_aK*xlsIxLMF|{7P6)ILH)}c5x<>xATuu7K-kJX323VK4=&QNsjk)T z04Kru!yaLqZ|i1Gv>r0J%?@p~>72UUxJKzQ^p;OCAnj-M1+6D^*IJ%ye>MeZGaA2X zZ1vkTpX&lN*J`h+Z`Xk8mg+23Vs%f|yDGfuUsa)!SzU_m=e0^&O{=n~#;jaW8>zzA z4OShg8?LIXi&Jsx5#{*$4&}Z2H%fNHJmunsAmz;lv!bBEp!n2aRjh3&Q^@M`6@BaV z3UeJn>8|Un4647NJXRm93U6puy>BQ}KWwbkh?>c|r!7L zEM<#zkeXlzw0K92j^>mah_2tJLezJ@$sKAHdib{6o=Tg>)6))m_u3=91*mu3Y-fAL z4yR{_!{+g$e2cM3Dfe;bz!ydjLiaL8-0AHc1+ zDYRqwO8RR;Usf&gKaP)lGYadi#9CeBbupr zOY0wUk9H<_6sO&g0>CV?J(T=Q{rkPkZL;a@WsA^9+Np+^INZC^QM7g5$xYARy zLz!7JSJ}5@l5$naK4nsAv2s#b7uCY@pQ>3EJ=I4mcd3t7m8+Agdua64do{Y6292|J zo7PqruX|g6Lq~4N)d|o!jKK{>y8H$X+Q)gUztfay_||;DSkdy)q?A^fwXF{=*V-mq zQ`$*3a>py%n~rIAbBD{`Pj=ApMJ9Fz%ilWp%jdb$6kXhtlsHees?L+ER(K`aM&zaL zyl=c=fj`%n0&vVWV85jeGurkNJJB%)x7rnp|Lh4R4DnHkQb0sHgzH3JOzccqK%E)zb0V^K!ZFhM-+ zIR7k_#P>j_cuS!eULIJ$9RzORIw+mErzik7jAG>ADKZX1F5;A+>pnS$lS%Hu2_kP| ze^0E|vgem!LCnBhmaM-#gc*aRwq9 zTZM;h*@>QG6I|bQO2-z>N7SA65X~>=Sl`LCmaZKGEw;9M=DOBkbBpwWi6HG~8iHmd z)y+mDz6JdzTOJxmw!Aj(XlXX)wb+ehX{#|n+F`^<8K&BnSW|J!OcP1^*0e=hWh#_@ zG5wZ4HJy_lGcA!WG{s4$n`&AHm=?6)Ol8ggjH8=R8%fQhjn1aQ#-!$5#>dSXV^+%x zlTrG{{H*P}Wp#(uI$J)3&+?bG}ZoN}Ph z9gCgn&A_31N<7PV7{At6g#YP-2oB#wLMQ(X!YzLjp(oIr=mOpmeVBOC1l)I$3%?aL zye3j|$qke;a5q>;vy`i&oF=4QC6Y=;Os=hB<)8JQ)nIx`q|9?nE4A zw?%c~$Yb7e*2e{KAI5LsK1q1S-IDm13nw*lhbBq65lO||cZnCczY?Oj8Mq#hmj1{%ZNA3k>MfCiqLRI3W~>>7G$K|4R}oLC)ogni*JElMMla(;ZRDY zpou(5aGCs=Kbef@)5r&Sk4Ol&6KOd24RIRkYwXTOxlznt_#+Gh?g?zb9;I3^^FS}q zhurLU5#IRr;_f3ZU>Dk{>x>=ev0qz+ah`OUp|ts{KC>xE-?#CRj@vL#ms(HMJ*#`BjjKDW)zt3PhSrVH&aUgL z-GIJ+ubZchuRo(*SN~i4xV{3d*HmiZh7RrVhG57%VzzAuG>5??hBx>DeHnmQ(FxsbEM|I4z{gmyqXDMnN8&thq zXEl4=6#XmDS7VKLgT;yFzZ3m)oYPU$$SllY?@DY>UluM37>IAc)Sw>leT2(+C*d|B zf_R3wg!qV5OXO2llWu`5)DN6R{y{A!f1{yUd3ZVH6J1UTU|t3Pu+~ABIcWNvx0iNN zZ~^Wqx<&sY-o=;`(1XbgLbI^JJa$}YE&F!ZJPskk$(bH`iTf)mf)^i?%Ud3s&A%BJ zA*hSrC}>OgCwP%460S+=A`~X43J)bqgzu6+3brOs5qwTU_};{^{E3P4c!LslaKFYK z=7hzrWUr6TU>%B#W-bla)5W1z;cG$DXkfq)YPP5+L>8DSow=vTsjQ`>Q}hYMa9RK% z8+4(50z9rW!HqGXIq63zr@puEjIYwO4_W8R^n#9!p6Av%?wRIsF3>pA`9jyrF;Np> zcPSC;4tb%)*M7$QvUQ1RdCN#+WK$Ody+NV}>X^Fr>PRiVYMf?z#U}O7vOB5)r5@#v z;!Vn7MSwEAFiX+GR9^g7 zDS!JfT`{+?RpBjMsmv=XQ$8vlsybBSQ0*vvtG-n>UjtV}pnc%Jy2sVW^cT?l$BOz+ zrm2lD%{!ZE)@J_`~R7T@};gE#XWbXO5s_j0g$me1Ja>y_lb?o{t(l1fN7qN zsW)pdXDzANA=b@Ul~swYuua6V99M8tomO1FYYTpdhew!(JRschN1{#<8L<{mCf_IZ zqNu^yU>tlNn#^paKIKHiW|Y(G6P;zq1Aa6A1RGcn!}y%Rk-fQ7qDS)rV~6u|;{<}h zg!=+~B1^b2aiQ>f;!)wt#LdE)iDcohgvo-!xQqO$u{k_$%s;Lux(9bs)L+h4^n5=d zVmP}ktS2ip)WMh#{EVI(I1`>2kW7<`r%+#u?m=xrB`6X020II0Q!@CYDMxu$vVxmU z=5YCBGG`6x1M4W!$GA-Z=>PC~stR`=tj3badodY=NFWNULZ_kcB8{GY-W=y|_Y7N# zi(!81sMBZIPiZvPL}j)`+0hk!o;DdpEe8yT8#D9^>m|AwwKmOw>Spz{N~`Ks`8d_s zGMjR6>2>A&k|^bc;y(&c(G$g{q8x>}@Q312p+Qkwn5x`Rv{#u?+@=(k>{1n$Kta`=kC=rc*=ZJk6Z)nHp-vW3<2T)9k7|pv|sI)pb-W zbiCTb`sH<_45Wr$#_Nr}O%cuM<_9gqED5dStbg0K*~WGpwO^AhaOB97oZl6A7g5#W z+N!Q}f73kiRB5MpYji$unf^M`Wa#E|7>j&j^9=u7)alr0T>@OQR{>X?+cE#SXJU=s z9=O?l0Un2?61;dnA%V;#9e~ovf%Gwyx2(BfDDNV4U06k>28iIW;3af(=sCujh@(tn z)J#@KOayyjoQ!=tejVpl!b?tSVkKu|B9^->5#oj>R&!n?oZ?UurgH-0c^qf#efF~$ z4m&-10m~hEim8bxLDgLY81dn`^qjC!^sF!)+$n4m{4(?pt!Jp8+8Q#5`YPlKbRfhI zibGPtH^F--uY-G1+`&63ks)s=--0Jn76+Xm?+SQ9x+5+i)(8p2R{jpc3$7DCot=tz zGm>y==>E_L8i8!mF~1XMLJedayn$YsdxVqYnq(d4*k*iWW9mE>oO(ApGd0k3twUg3 z(uUe6q}}w!=4HC~O>eYyjUEl$n68=CP^$LSXR2%JBh`)dYL%(JS!J&`s_-b!JfvZe zI7kb2^jW*Qaffz8gH3b2eyzq+H&T;b zcTlsh&Z?=cyQH08zepF>&{t1rj5lZ+nMPyNKVxFcG1FV=Hgj&}KYKTA5?R&$GmlBiRYjCG3dU&YbqR z%bc?bbZ+;g+uWk$6yDg*S9sYeW?puePW%O3yYuV2()omLCA^q!+jz8YRNmpPhq&*$ z)Nxj&DA*S}Rj>{vl`>Z*d}Y9Ko9XG%IJkSnN~%2M2e>p)NFj*Nlb-R@i2O1Yq1U8G|y@ks*LLI%C?FRifv_W@+2Tz7kLZt zb&z!T*H6;<--fsT`L1o<`SWMnk>CHddvecoj4pUC8}N^$m{63eyj?O%Ra=&+R#oI_ zEL9vGrFMe8SN&1LuErW;b@M=TYU^*yoA!RTA@Ur1gR+-%o92-#STA*-H&VQ<=57ey zHq-abzQUjA>;dd^H2^o|P zhqd4uQ70;epuwjRmk_>@=)}vEcf_MmIw_MDfX?9dqda0x13}IlD4VyO>Jc2IZ5BU+ z@qxwk#laRvUMQE`D^_+@}_cyHT@5R%pMl0Qx1^3$X=#pwoN-6vL-OKX_s&ix&b7=Lw*8E+3lB4TTyw z3D8)}46PzJQQnb;ld+_W#A!q$ z{t00bE}9UDt-}w%Y{Rbt9H^&$J8qOO2$zXeV7bT*Y#4F~yBpbuwWEE8>pmrRk3SMO z7FdT9qV=^5>^6Kot`p$_p$qW~X(XwHf*~(}hLbN-FOt8~a1=AVoidV<0KQ-bLCq|H zs$hSjR&%D&{^Qos?(#;#*Z5`dJi$h~SeU{9MYW6s@lxh&37vH$;1?@5Fq7RicnIfF z2$QP`ZRQHXFY(eM!uUNRAM$OHeFT@Ht_mWfUkUa`=L#N1cL+X2R|urh*97dCbAm20 z?*ubr-U!~soDeW#cM8&Cw+pVu9uO>!`zu%;-$%GF;lA)+A|UFLyjt|BlU6C?XxSWZ$EKxYX4KgfobYsYg)IELjx9u)C|}fQaNCE zNald~A!vLh1`h0VETE*Dz37!^`MRNujsSSbY)Yk#U z&{D~I2of8>Gr|qvNP&?Ojk?^gax2j}-o@k@thb~~39i*a1i zB5W)n12YLX3^MXP|P)EdC*8<0P*C40Zo#)JS z8=T+WBG-5K9M^95IoA?*g=@cijeDzmi081|=3#n%doOydh}#q9-+~gW{(4tp+Pu55 zQAiAKIhKqkk@z{t81!#~u?5~B%th}Q zV4L@re}y;JzsalhJ@B^rut=zXJ@TKw1z8AWpp$n$(4PJPe>Yr?eeNNa5#E`0h zLUK6fFSr(CrWRmC^g-BU<`=AwMaJFZ^hf*hD{&qCjX0}dGw!r73s)eVh5If9aW{pf z*s;P>*rx&s_6h$vW)iOp<{@VQaDx@&-^AGOy8!q05oi?O45$X#L0N+ACLQyp5$1Zn zVgudN0FN`>hkmc#&W=#eVta)9imkWHZC#I6T@;R?*5wYFrNMs1GTJ`Z(rkk)^K84! zdDc8rpf%PMZOJ!2G)*-!jJFNn_4)cmI7V;U8%HG|5b!n^-&zCsFDYjkC0nRD`dFRGqSXjak8t$v9jpmI2ofj zNH(chAZsk{CR8penDos*Lq3)fM$`)i>(@sfX0psvGNM>TPv4buYA5I39iO zU#i=!si;$F((3nX;~T3}5K@FH=L$40m01#>wtDGweBOIpN8$Sv*9? zQSUkD6l9(o<6G@r=^Nww>7xT-{#?vU|2SMf;1T`|aE_1%2#Bq~4dPeSEO;2$PFxE7 zBBTI(g2o?(f8zg!O-F0S7k$(G`A8-LA+tT{-oCE6o*>6Icf0k9E8qOv=`?bjBMb{2 z4|I3!GL6vQSN+`PR5EQp6kDu&R9G1QXQ(a&tP<<)?u== z&NPi~turo>9yKmP=NkGp7aAOmQHH#Ri~580486Q|qb{kYT>HB!TD!XPnnqUMO*5qI zi8`-@sa{_EQ596QS*7?#Rki%Rr!*BTP)Z7hDzo#)D#zr{QfA~&S8hdLb@`i>XA0gc zNBvDwCH#A;np=pdnv2$|*Oc_o@XDl``tk(rmC9qe;g+KwDcv@FBAMpkEiE6cJ4$~)Wt$qVc|6gwRe zXdf9;MY~3*L)>0XcaKRo#G7ZBj_ft9^o_JE_Tz0cfXDVum?6$K%mddwtkS(47vaU> zlaMWVCR)>x`-p^{{%C^2-%p?2+_7Tj$6+$@X0wDpjmq10A9+*$?0}vqu zqrrE^L=w(pRuHyfe-h^6`k>_c7sNpXG0K&>Li$5WCXc54C7Zz|l;c!7*dM+RzM~7E z4~(_YcjjG)&n}0~aOP1%dC9b`{5)D`fdpPJ2tl7=-)VpNooGe8Jya$43nbx=fCh0m zP$K&p_<(7nw9&g!I>GbF+ferU1&~L&LQWx`CXOSVMpFTm*fQKO3>kOJzZ6@DG-AZw zX_y-KUqI&)0f_UeU*#C(H`|MRk@m^HowhzcijD8vW&MrZvz$Pr=6T3$b1c$oLcD!V zkG&I(3Eu98AD$%rG*5S(-91Qq)4fR3(>+RE;zFzOt^!4gQ!Y<-^5qvD=`xFbaK|=# zm-g=VBW-$H&$b6PY}-bgxpjmMXd7dTY&&eb()P_Zw!O%vYtOT->Tucy%VyXw%dgve zD(me!)lA1#jnmOrci8z)AL~jpesg^`4RMEA8r&S~4o`u#ix+FRdoMYzA+64dKG@yM zpXmt(I=nEZmk*1*>n}&Ek&ke-n0t5xy9af!4I(BGAkqfnN78oG)&`NK929l0yGn;ZZ>K-Wj|c+gJH2A5KPfmF~1+QDv681*EyiUw2j;D^+a zjFB`ROGC4OuM*^868-}>J)sRtqPgUITz;P^ouynZH%Pwrbn;k zt&Hj531esQug5;-|BAiCKN~xZzbID2BgZc0O^LB`A4Q+#dZPllF;T}kX^{==kO%_% zPZ*aqE!52@3ofJg4f+E&1iYr5mVBY^6{k}bqR!NnA`<9dxhm-t1;;S4f7GrPESOh`Bfg24d|{!^v)9R0SDJR%s$yO$hOx#->P)&w(NKP zXO4GuHP<<>7d*9Rfh{w(Af;6zqqCiq5T5Bf52 zPkjUNI$r=`jNd>g@N0?v0g(I>5L3FM{VOE~gq~w@)cH6qm4m-a%f$=fg@m=RgU|{e zCibNBNdxHFq`vf4QYyV4nL#f`z22iK>*>!Z-|2lp3BwH5F*ZPzOf1#LYNL+g{GzG2 zGvOS*2|g;!qwf)aV&n$wXCgtJSolyYYg~8^yE?KT2Z_$%JdI7^hQuG{u21;NJ(39U z<|d`^+)0VNq+|-umsH0+m-LcrPdvm8PVCB!O!&%ajhoCF7pr5xi_T!vhj?OSmW3 z-0Z$5PO0rCaG`KpoeK8$axuZwRl>Owr@Tj#suyXGtMUGzox zANUTU$$K5@BcBX31C>Be>}kv|+;;4KG+RHH6px=nNg^DELW!9)H<3WEAT42BA?Gm1 zp!3N97{ty7r?Kn6lPKrnKXe^nn?V}e1@2}kKqK=fn9h6*-ew#`=QB2e^XYfcIpHth z4)`7T3a$tFbP4pDz7jga&_TDD2dFYuIPEy6iS~&17PboR(<8*U850BUFsp(dvd)KI zWcP|#$GH$Sk^4GEzzfZv`RDj;>UzMax00;4x(#|2_FP z_YLV8`x$W;b3b7weIP!Dro;XOvoJ1FD1asW_A#(ikP2UwXQZdIyAI7%AG2~Ct4tql zd-WHrA2io2Nvap-YI%j}RtI8y(w1QSBRy(RG<)>hn%3ygHb&`N8ie{O4Mts`hF7{3 z4VQE$8gA;^8y@Kz8yj@}nn&m_wY<~6msabiwm#M$Yt7JCx7OMwI9$?JAUg# zvIzY+`6m5E#YO!U%e|zPJkAbZ@#h*7pSwp+*im*5Ie$s{kt@7ju=A zgGDWlxDrYvJ_p=|-vZshi>aURcc=&+OPflVNIOP&K-)y9rL7`ZY1xE8_&lK>{0wDX zQi)sOi9{Pbo%oi1i1>lwB33fzkzTU$NE_Kh$agpe;7;Nxv62T7dUJl`ikP>tY4p9AebjD%iqh^o zMY@mlBkcC-v00uR;G}z>@3?D;_o?%|8*%uYV;yrHo9w4;nYQPa*H*mQVOeJsTaM~S znwM!8o5rdq7)8omh6>qt{nz$~x+|@FwGl0QG*24$s5jKFRL!mpS9Yl`lp8DV%c{z< zI$R}-+k=XCv<)k~-umXRRJyESnsi3~`{VH_b;dxKEj7=bK!rcKE<89OgLIhn!NMU{@#O#16?VF{%n%izl*Tkw+43_nTdJh z_4quVHK^0!lPk>KVh?czSc9EQQCIMN{TjPMv&9ys%Cv5f|FTd!h?e)QV)K%gPNu<4 zA(dk7)XGuXy_GfE zmdYi%%T;f5XQ~DIyqX&QsJhbzaYKJ2vnkQUXX@#fVOz<{ZE_;_*dm!(v9}$anu5Y?+f*-bz1HRcsnBk6> z7=vRvw!qm5M{sw?*L&^~y86bGYJocPbzCoSE%6RCn&P8Mr~}|8cs9M9nZan~L^Ch* z87zmegEdH!&3+b$u-PFqIbFkAINtD~+^op$+{UOkTzX71*BkSN+b{Mw*B!HqTNpEk zTM(1X&5E&es-y348lw7f9!6HPmqzShXN31+M~D4m6@-Mb(t@urm4SVj1p#VCj^rNW zi8z_@2b~Qw3EN?zFbf_ch=-5!-_mqE60JXPEcFQYBV^=Ipz)j@;CA**$_mz4au~BK z=^(u)@dm9IVH(sMUrLU~jU@iU+`^>;M*zKVHnI;H=nnCQImn(2tI>79^uW1Czs+$? zbKD-P`fV#kv+r*^QmjpFQ!HTXC-aP!F=nv2(qwI1V&6_t#SaKLyNzNg=C@~Z(c$7k+nkZvv+rgD^ zH|QE&0WD>op>ASl(bjPf!x#CJ>F`=}t2RpF2MgY)p9~*qbsz5SnsG z!`9XphOD-(#-;6zMs`Q0>1+pN7R!#C8)QkA_h{|nnZkuSay7O(HO=u|yV@4ph+lVP_+Oi3Gk^V%UH`pBz9@H%qEG%pWzb)r zl2JHJ)mrqQ>O@Irb#&QD^!lknuO+I+Svg3PU7f3mtUax5tQ)7RYar|OO?Ew28ej}+ zn`{zyJThx!Bx|u^tnHoZgngH$z|l!(a6Z!u+#QAtkI6XI``k1QVVj5hj++sm*mA?a z#xe&ew%CD<*3p=8wjY>{_F32#hY!2ebqhDxGaf$%VWPeHIzm_MYhoS#66rW;EqOXP zkkXHq431?)K`Yo)Y6cIX0zwDvxwr}r4}4D_7W|CC2;Iy)6ozAY!gsSKMY>tTq9(Id zQJ2_@qN~}}(L|0Y2H@DDo7tPAzp`ynJK1ZaLfFNT1+2ixd93;9+3sZcGG<9w8KZ9) z%(xXgo}Lr(5Z)i$LYo;xqwNV?K&=jFhv)&Tpnj4DaIaVbUK7otY!O}}3j{YwyLoSj zYL1#Pl8q&7V0OY^qCdt}&?LA5XaRN_WgX@uF&Q|Dv-)-e9%M5jLDrze%_$DIyV!Ej zRcp{X)S5x4n?2Y1wqvX1R%?X$PIIHt*znCzTlZFPMYA*F>LI$U%9q->3Zgc!e3hnO znM9LOiqY&Yd7|c*h}6%En^hBw)v6K2`Kl?!M^uxG_p0_6Uscr>zfgsg6sVS#s8!`9 zMD^&>SoMd}!D@Hua&>H(RDGpvkLEzRR&%MMFIqdis})sIb?>XT=rXE1be`&DeMik4 zeO~Pa{k=Lw|Ed0zf!i2ieB4xO+}-lS^sM!-IlZIS(p?c|>#06xPtmnIdKr1HQI@&x z!S?SStSbUJ zlvlLFl=-lif}<}6%ji!~cdr$k$D9StU|oRDv2Q@XIKLqi*8xr8$5FL{ebmb$HFc|G z2yJ!XZQ8V82D~ivI(##H5dCc=iSaMGk->~R%p91&WW^=DWc^JZ%ueb2h@F+nKG#{y?$&7?>q626=7WSMj9qb;=*ck~;Ihc+ zw5{O~6(70>To43P@+4nKsiI8c4SqVo#^K`ov8>pW^lA))_7Hdsp7Tq{Z+$BW^@tpu zJh%#oy^DO)JSpBYZl~*=>$W4`nQp6g#9BJ+Lri|#D8oowobHJg(v(;4YI zGtKOp<=QW`kWNvTs|#*8r+?fy(r}?U(%32`n7XvTHFc6*F*nH{Sh^}_TT@YwPFM98 z+bGR8`yuU6hgLV$xx}#76=OQ*-eY;<8EN->$Ggt^?s-Q6J%Dg*3r>OCO_ch z_!9XdlL_AE%!Ru1m!g@9G<5b|1mBRnftvz!@S#92d?wHe4-RaCYXhFZg97@%dnM0k zyTmYUh-ePAo3I(WAUFn16r@431Wf3OKmd&rj(`@4u0xgLVCt3tIdxsoZ`#|CS8(s} z8hUUP%uI|O!U{`x$c|1na%QCfyi?uc_`7>95m0;26!z)s5)%8*6Ln2{Dr!i}5oy!L ziz3r*3t#uk5j6HWz~9(Q!kgb?HK(-8X;x`+He+IZFL+i|K4c9!MoE(_AZ_RI2yKk7 z*vrs9;52c8?=@zomxb(de|45R?^_2rT8y=}%eq5Wsd|ECi*l|xQhw9qY*(QE^$|v; zw8ZeeWvt<9bBTUSQxAP=;}KnZeY19TU6{78W`+h|eM2p-ELVBU!nceIEc0ll%OMT(U&b{Y ze3{k|^55PD+^eX@MX&ob#pG;jPI`Bu#q{Bcbnh2-TiTB^?Kgi{bX?6Vk=^_IS`HLT z6c z9MY?uosAf`(?s^{v>=``>o2qpJO;7Z%aJdRqrPj-bpI*WSAV8E6u9nr2}B@kF$KOU z*r5OeSBO@(&f_xh9|%DND)~2|54et)P8~!#0mEbw(?`x^Ltr`A3~m?vgQCQ5sPh9Z z(8dHUgu8|C=&519>1!kYGCoE1WNBhGOFxFov5B=dhb-D_NUp5EDK#xCj%?UNBlF%8~k(0d;Leq=lrk8Mt=qQ2tcAlVa8B$ zG5=9Au|ePr+!}Bq{u0=Q@EtX#(xD8}c1TNZhwgys)c(}-)IYRW)G+!dY8pdIjbhSh zSQejF%Yte9*;HCI$4zbIP-xe=J7~Aj{gs`68J;DaNLPvmGOkLZmXFJkth0)v_Q1H zQ=w>CN|bnc*C*m7-G@u&^^{6x_1YG&s1H4Gbidny^8WpU5(eZ3jTjgkylT+C;NF8v zgEI$Pf=>@F4BjyKV6b%1&|t=(_8?&3oS;i-je$x1nSpov!U1o3GbEQ&@#48XltOLS z2Eo*nBEB~HA@6(Qa_-sqzMLVk{n(P|;jG?~{h2SrgBYvAg!HJ;6=*H5hE^UFK>HcE zA7!X=s6NRVXq1En?GzsZkBU5$<-%-Atbj#%#oI-Oxk}P=zKvF`q!P3|afoBONR;GTkfcB_%g?l|8;x6n7w-Hyb&tB^XE z9ogp+qGqv$zWpw@?}O`~zu9F1e6E4m{_g#_FK!KfnrAmr>2Z)|dB;$yyq~}fgikF* zdeL_K2E$?gRQhhej9%rR#YhD{GtL4(8O6X@Mg?%5{tdVdKL_s8_5%N?vj7J)0boPn zz&KFv|Bv$1ZzoUkk0wjew)`6(n|#X`OFr$}LEi6cC6D*@ppbpV)g=J7fDx?1fu_Sd%i z)-%@Y=0}!W#v=1Qz0oAqN=$1tX-2mCfZ>%AXE>(Vs=p{V=w8Y8=^8sQXw7uGHlzKo z=2+WI&D~a?`kM5O`b^6X_1NaF>ej|e)q#e&s+jtA<@MUFN>6o+azhn5*;qM9vASF; ze_eV?4wa0MA1xBeQwp18{=d6qMFk|;*Zhke-n?lYWAnOp)aE+c<+)GWL-J0xkI8%5 z-jY|@{wiPBzPKQ$W5(Yj9X0>_9qWrm$=Zq^qrLqMd0Sbl{9VO-#fYjzWmdIBRaDcW z8ddj9-B!O(v#K#c`>?4}JEeKM?n5(4AKY?If4_xmh?ed*%#}I~3#0>$N6}tAzO~qR zyLGs!OIwqvqV0&evK^&8$to2T4;f%SjI4EpZ)ilpsclj79zs++@EK zQ{vkO%=TUKd5}HcX-JxTvp3&y#Ur#;xQCmoUE2(|od2}T97EM3>@|u}wk@)y)}`$i zEx%fg=5^9_=E*HY^OWX$rgcpbrn`-|jnamV#?B2>jqmD>hGq5J4Jq|PgSDR_&+tX z@Qy0(Z>^G4Fk87IKULW|f3h+n|CTZ#AEP>!KUdYGAYbJu=&Wx1dr1BJU$J^^p`z+vwy%Oc2#bPQQ6ER1fM=%y=1!kKIz^1uVu%Krvw%KzPd*54#U4tay zj-gf1fBsuIHOf*ZU>D;faSHrC`~gBTQAo@sJtg*}j3Ipiy`+I?wq8ctM7c&6p*h_j z;4Ri_D22nP?&s!H$M6o)R6G$}#h(pV3C_a_!baFFFu=uvC-5mjUzjRT&{p!F(th(s z&}`giR4c~`$=Jgo4eJs3n(3yn8BEG**iZULRS3z*nJgv?yU9K+B5taHiwUFedVh)@9@1b zb@QDzwjdh}SCKRNLC9;J+s2tdaL|g(!1fGgV1$^sa->SBO0%-D{6e7w3&I9Q2+uwt5-n3}l|A0;#vI z@Ex%$eO;VO{brW{X!ZO9nvta_*NTO9mHt7v{1L+d^CuspWgxrVxA6Y~mMCnZaNO?gH0R@!f;BZPL)Ih0(I?zNF zjjE;rM{*t6qZY;U}ey)?nhUXcKB`X^vHl!QX|LbP5tCJtgp#@=I9 zN6%#SjY?$gjHqH3gbib|Lkk!^P_E{(z*2gxWITP6xE^j6PDB~0WwbT?skB)<9W|SK z0cAAwpswYdfb!XYKrA~JoXa{-X=c`vBT@G0NXAXlVR|d^GAtp^r0pW~pyuO)APoL1 zWi-k~yp5_l7+5CZGzN!L0>PLFAPG$~y(H)>qbK7+vT!4OwYlMEMOK2!{EjNyGyG#}C zy_Nxb}Oce7TCEez!l4*QN=h=L0 z%18d56tUn_$^gNe6p0``rG|gA^C5m!ry%}|aVoca`~eO%_8waw^&jha z#2IF5=nBS&;4$?4fLJ(5jGTH55uy@y~_06h4R!~srrXbt=8qZpjqq~sU|x{s*c*XDpj`6 zibJ-kiZ!+ciYc~FisiN$%73<{s#JTv`jH`pmLIGsdOgUe~Y=RRTuJb!G_ zo)7aQ)<^ti7ZF zx|m3%mf>eow&U7}1JK&l5DXtX6#!8~MQ`7AUyj#%8MW;@at5 z<{s;d^ECMzJt3HD-Z|Lr$RFHeq!(e7?Tu>LA=< zS}?v8jwLV|{fXj+DLpM`IQr$>B(qa&+eQzVvtH);}nee?zT=$IFDeM~+*EmlRJ8!Mxy$Cl8g zF|X)TVrI~*qMP7O(W~L)C?8E9v5@vE{3LaK*geP@QUWFgmr&S&+2sFmbQR!DEM0qM zc9S&Lrry*j?u8P;dyZsllJ!nSfaSjBK-rygw~|xljiz&DJqwacYvp;BW@mRQ*`GPBcuD%Q zq7{GUnI`_)T-ZDHVZq{*Kl!QO0`mtZPtW`FS+#27n<%RwjpYKX-TafoF zqOeg~UDH1q-HTY(tm6K;f0xAO?=78J7*|%mXs_8(+^_s~X|!d$xk<&@a$oBs3%12q zm~1<(r|m{t562ao-7&^~$jR-kr0EXqN^|^nJ$4?Jb3v#5n~Tv)avFO<5Aq+Z9(u!H zAcW`PW27Ch7g2IaF;DPRy%r9;8N~^jE#flWRE5d?pz@IC5tSS8QRn;CQE&HOsBUH) zr#=<9R{ba_MSUmOM-vy)Lvt~7zou`cG|i4mf!Yt18fbmP+G&NbS=z^y`eP{l7pU-622EupzCl%%VD@i$c=f2&Aj2ZYmf zAf6%z^B5PE$4XwV@y@}{eva+-4)zV!UbYREVb;UuVHN93XInNGUo8J@$~RjJLd`$( zV#+deVoR0Tw@XYJxa4SBr{dwirxbbrJZyTJ;wZfLZD?Wf*DD3`XWs%TX;psU$LzdG z@2BQ@B)a9Xggv=MZ!6`BZ(rstc(XXi?M;uItMQF<=EwWz#KiOLrSUYoBHlY^?wejY z=Al?<6&SQeO3S2+S}d-)k_SwRDbEy6>gf5 z;vc16XdvFj7Q7CX@@f1#oyD%W?$dA10=d8An=9E?D)qKjl@ct`&Y|T~9Jyt;?Db0B z>;sEO*^ZblTVE8EL%mu+MPP0vizTaT`HqbF=Kg6L%G&-;Ded_)rgY?wt0m38TZ^4v zONyR;-fG&N)UEK|hv5Z--@nbDocK?^TVh;(rNkfkQxk&=auPQd9C)uTocLj3Va&&$ zh0Buqntpz|U<&)pEBJaof)OOm1k#|%2Tr}79qEW zwOM{8Ta7|*d$y^g<7{ycXXjFHX+_x=X}Wodt7W;LOv|6k4=khTz6u9DU_H!IY~A=Q zM-$XuYK>dVoylpo5?G&7#1UdmWlL48Dn|3pt-s!`)*6~?zj`gwUGQC`uOBeUy-VN} z58vQ6z*+skU=9uO+*|3mCkeB8#)dgO55jSDn9H+mSgB`GCG6D)u+oIk1kZ(`%RPsN zw)312TFG;9XhY90p&dN;RqErpB5b?osmd158daxzrB>5t?$Iuc&*?XQfg z;kT!$$~Ui($-7O%D_+g(kMg`&JIf=kI&$w^*{O{S4%5U2#JH{Z*#rKqLtL(FE6jF_ z!kxv+yeaBHkIBbe_nbabPy1tswc>%jth~fF)7-`uR2FAdl{T}ED7jq`SKO{5zbM5L zSTw_;HQCA&3i_7s&yO`X&U;sOG^b%%dDg7b^o*M&o6-VGy8rG~Y)_q1bRy-1X~MUw zg_&RC3Tl5U$^Y^pGCwQvXkMLnE%KhdP0Bs;W^L}C_?@}mULVfA_3|j(vdR{Z0@XQI!^K2O0-)nrxWv>aL#aB0KRr0(y zS8d@lq1tnwzSXPwHmWhy*Q4ecUq?-|FR9(w&#%s2ztTEoe*e`q`cJIa)W2r^8UCjF z_x;a=XZx!fy!V&FZ}>kCKkmOTyuJV6@Kb&d>udd9*Bjt_t?qE21$D-GNApzUm-uhtG63?NEK=;$aYmJtyRP91F#TvX6eWez9 zRxXfkyS~}e!FS7d)&<S;M{P*15@%g!v;}v;B;;ZHb$4|)<;(z6hi=UET?@g_On796g z&k`(!y%OJhLkJq#((^^yz17>EN%Kbw(B^OD9W{UD@WZvej~zV%uJ3vv230oUv$+D+UM9I%Em6lJES! zAma04Ala{IBJ@^#%2!j({WpZ`%eopK;;qd`8yy z^YN*7(fev0rMIGXYcG3^g`SVAtu`#KGSQ<^SW|Z}i@H8RC$-N5`e}Olsnl=1KdX9q zZdY>fTR-Yv3Wqe)NoTkESXS8iPvI6jg}2eJe6?Hwx>9STIg;R5@4RST>1c16273}` z+D4VEvu2wPS4=NBWT}>SzWikNFLPFg&O9isb=l`%D@&WC-Y$9n-B!FcxmWS*FMEof zf66y?NLpdK|DmC2?E4pmEfRwZjqgSlG)lZ6!v8)TF8uYepm0x;wXiVhOW}-9d4)4Rk1~m0>lW4c)~vW^%CM5UsUu1) zKgF`1zo(Y*-x*~e{>(M&)BVe5WE7QqXT5_OqW>x~b5B^y@-NwHn$Fu}imyBVE4>Zl z_`Gzw;=C)&{#LGVW>be;z+Q1JR85b->lNq8LbpO8Oxsv-Lf=!F;}NY&_l$Pi>FuvB z@;R;c@e9#}`ft~K_0Q7;2ei<33;0{RJK(VPX22uu%79F5bihZg%YT#hjsIkANWcMY zxX}Q4`FA?s;EVc=Av4@7LX+Hwg=M)vtt@(ssyfo6JH%WAYxXo8tR3R1sYkpPhyV5x zB3^l)Z+zCLtSNA)Gz;@9j#}h*xA`u=8ZEB*HEZ#&-@E1!ekoBKeE)71=aba*mG`5@ zzrE^5eDLfWKFv_MZiV}SnmhFQRsD4KO6xUWgVKQ$O{enk>8^-0d=YNxCX){8Y_wAW zb;CrW{rMjGpuEUsaW0V#+gm!9Sc~neEt$4wX1%RLSr=9a1r?wfTXzBH@& z&41am6Gr7Y-!;iy^q%L|{P;F+_NTb~IbUBFT=?!Ryph_dXx#5%#kW+Sq^s?J?-@MR2}7;GyU$jh39~p(OwU0cl4fCueVR*1}%N_B7*!TH3{**5LqeULR4bF_!e!9 zPos|;x3qj~OmF$jSllw!xTa-Vz`khDfDSEM_%Djm_*ISk+oxgU1h4%K$_!8In%uwE zEY;1finZ~f>2AirCCWCwRm2$vHF=_yxkja8dr3QaCosLeke)gs?1Sw#i_s>PeX6Ki zve&ZCw7ERI;G#J)?_t@F-IJ;-U=d6@olh^he=Q^VVM^w= z$0XbEtVPcF7yENfud?%gz99wDyLyEI9~YX&em+%nGWkmJ=#<+f*HZs2E&J84tU+2{ z*}#mW=80L0$|vObTO#r%TVCc{EsF}{D;5>4w9YE|%QmoVo_&7#bH}ra&XSuw2{;)A z`d;#cTE_;w2kVU*q3yt)XeCv|2~b<~QL#-0r4Z_Hx9ghPYNs|t(@JmAjB$_Cj__Ek zTWDym-{HAdKi2E8KFIr;-pl8qewMGKZ{)wvy_&J9M?v5nk8Z)04Shpe7&?bmHjJ%Q z%Wx9(i;5~=Fto24<$0%CnP;yW554R)_j{kMz0#*+-RZus>vi{Q9p2o3cZ040%Nw>c zY9h*v3nE4bUX6Gbcp@S&XmUh{ATgq8(2#~Ka94xFftSK-1kS5}&FEK819|4^0pn}? z`oF1}@9S0LolkhR*WQh*yz`nCmhAZ;^qIjNe9EIv&=dDH#$Uk8nyDM_S4)@evsWAI zU8EV}6{{KKIY2YWP*pS0qfEWk{e$|R{;67}zpI|EyRJT^{jPqm@zB)LSk2?!eR^35eRMkR3yYGHV?`1gVe!z2$#{zGop^@(n!$ZG(Lr_3V&l<)fo?(H1JUayGygCI}_R@z` z^~wq9;FTUa!RuY6JxIiQL~V9jUq!HH>w^|x3N#ix5kx14mD{O(!Xib5Z2Tqg@akss zgH=&}!6Tw>1U-rx95kYN*PszCjs^W4-6*(a%j>}_T3!h5-?CwFMRaD+ztO*g21lEM z+@h-lKWi~Gcw&p;!S9;)4i=k-1p7u^2uhA@7Sy%r&A=m#lZ~YjuLD{&{NX<}Tm?R2 z6~Eba>iVYFYT|RDW=rqb8eO~^RPX7TShc%hS(Wh~Ei12fcT^g$|0lGcu13fr?Tw&y znz4aP)TV%=Zngc>RLgw*RTbVtm2JF|6~OSM(0YJ6s6IqY(XJJ0XwpfN+kA3V)q%t) zf8y6-IDSUPqGMe|U3@>|dr_;5S49ugHx&&^?@;tC z&0+fR=Zwkpdx>fD@4lvXziXMc{;F?^`x$ET`B!}CjNbx$?`qQ^yPb~>Be`p>FIY~_~pB$(D^;F za9+yh!io(oN}7xF^M0Ff`>zK}^buf}SZ$3Yw%WEohlCw_s38lY$W`0@U|- z7t94-%{3{_pe-m^pYp0;cS>;KZup$jDYnAQl%b{?KVF;0{s=GH3*2n4f4CL9r4BFd zmAa+)cmInRSmX7(|wDjZe zR;Bg+G%bz&)2>whGp=-S+BVp8z7O8{e( z>5a;QGbWZrXIw4ooAJJEd&bkUgbWZ=&u}+a&-6AA&U7>Hg!V17zFE#3ZYEhH&FZWH zX3wnI=6YHC%)PQ6n(Jr%FypL0W>r?9*^s3y56cqDhi7G(7iE1mkIqUpkIKq7&&lHE z*esv&b6L9b!Yp-p%j|mP+p=TI= z<*F^NoQ(2MIgiWt=R7Izo%5l*dQN<~5za}@{qnNx%jI(R_42AYH_C_Q#Ff9u(OIVE z9<(U)GA)(z-dkSfF1D=A4YB-_D_C5)Z7o~!9$T8{_ozt7|4`AXpo8^G!9nZf!Xj&K zVK-Yn(=uBV({)>vNoQ|s>Ta)R+GVd|a@yOOnmN{(ra00~=NyKj4-Q?C(b=|Wjq_B| z3#Y9}DRnQ7kuDX-O8Sxu(#VoqQe4SSsdecB>2~Q{sl0T9G`j4VR93c0`pdjTx@X=j z>B}!k(V#W^u)LA0w`G=Vx8;qCS*psbDyGW+R>a9?DwMRSVg+q%^<-_WYgjvLKAT|e z&F5Lq^YPYNXs-1p+GzE{&#fbI58E~T+NL56>=VgL`*kwWQ9!CY{REBFP>7d?3I|-P zgx&Hy;V(Kwu+w3}LpDq3&X)<7`7mG^sVvx$k1!cG6RzNXLK^NSC`nVH0qG*tC5we` z_=vC`pAe?wqe55w9{6MGiUOV@+R$1tADsgQ;0*Bzs;~G4_4~Q#E!6E-D3)Vir3Lp= zP9m{Ncj1uoiSSIhP0Uv=Qxrq3h(h&5Syi=ARavEXYoI#k)uGgWa~s!G;2a{HxS;bzxfcZ=2)y3NxyRWH*`QBT%w zSGU#OQitgZ)DgN?nmM||n%BDLnljxx%`IKLX0+~{X0UFXX1i{MCSKPMUT>!f)lb#T z({Ivz(686{xzE>(cOM7!sS`9m-J>=8-7l+E?nwPgzuV2v{gm4|_uA?f9%t2;J$|X< zJ+joBJf5f{Jl3m!15eHd_fzUN?!VO4+}$*h?sYW_-G^xM+z)AbdlYDvc=Xnu^Ejqe z8lGwU8`8B44CUG-hR@n*hLhT7@gUN#KYyL(R2kMZ2C z*LiuktGx@{bv{o$QhhoYM);02Eb$FA%=A6(vB}rh3{ft(5>)asB7l$u1oj3t{v>RM4Rp#qh04) zLtDvLr+wywv}b&>G!J~rpw-ge_Gtq;s9m(o2Q-a*pKDk7*4I7q-Ki7&l6C8#zN*|$ ztFPx@qMPAgpu6e+O;_T7Mpq?ZkFHO^I^Ds5zB*@sQCH9SRom3KMBCQbK-=AD(sVE$ z)kGL)Y8o5+X@(dLnn}h#>bAyWb%?P@v+W(Ak+RsL;D>R1do*O&qt{7|Ul8i+6%P8tnjA`00#tqti z#x~kk#&iua_SfVDJW!_xXw}yP7Q00TG;vGyFH=4BKd##8KUdY)zlW-+f3T{KzgAV@ zr-Hr2-<4{=waQPvOO)4qzbo(fMyt|%=c%sv?otK&9#tLkxuWXnldEd))81{a&pWrX zpwarp=Lzt_n$(YcG@7M8o|;gf3iVX)MD-D`ed-|4dprmG7D^2#-C7z3xPA1Xs#PA} zRdYS=s_uL2SN-%jqKfmlqh{~SzS`YuxVn$mL8#l#Qm1+;G_qHyrki(^=7e`&%`NY>ntR^cfir)UCfj?E=Dv4N z%`|VMQG4H3CwNU)pZBV-Uf@+(J=)9SHr?wm@K?@r%kdoJ_QbQL+drO_-Nt${Rc+5V zD#7!P>bD_F_0phl`)IJKk_}w-#1Q0m*WggyFuYamG`v=AH9S}CH{4atHe6P-MIJvOTT^O&gW<G1C?4s0C>H4ED;nsoD!S`lDE`tVDFStg3We^zf@=R&Bxy$|wreXX zR%x}0quNw)n0BA|Sur%XowDAib0R>2b#095=kv#3#lsT;j9myMt&f7q5%&5jW`Y0BlSoQ8APfG z!$~3WCy&T1ynwtzD#&@q<1+pnU*aZwh}R{1`9g9Hlt>)BmJoxQ3g^%^Aqg486jWOz zxI~D=_k}2YRS3gzf-l}Egy8N%EnEwZc4EL^NDwY0HL#6@;xyupe-aat$OjZId_sdj zA$fwZ3~dtnqj+I9$`pX>K&Xto#TUTbc$VwM3&6SaFCPi}`TiE?@rhzrIB&!kiM9D? zF^FT)lkX9{cvC^oMX0w)Bjs!Xsm>+bmmkN2c{SXhUq(IoIMkmDXcE7`+w%q7!~*y! z_79uF2C=5B0dr6#yGno2wKRpsfI@*A#mp?n(@*k6I!2D8Zt{Ja<@!wTxiaWE*F8{m z-$^&P_R)#1qqM(k8vV-^KnJ=$$bDVg<&mxt@={lXJjIpc>g+o1>fqYus^?novPxrI z8PWh(ku(jCLtKxgAlE@DS6U!FkcLX9q>j=>Nt6ysC!Bvt6P@1D2xp+w+1Xx-bPkbv zIscZHJ9kNso#Q2?6fHH8dP`HK&QiJ*ERA#(Ighz^JHNSlJDbU^oCjpRvrx` zaOfw?H>Gj%QR##05Zo#lk7aF@;HkXE}+0q@rixZ;C!3fKu# zU58!St{?E-iJa+bF28b(l{dKt%WYkeunRd@9xbWl0%wNnKj#tGI%f}8tW)FK;rt`L zbjC|HrT5Y%>9v$B?UO=XW2B+3hVc1C&U3DRo%ybj&PX}f86)R7`p7pN<01B#El-6u z5n`GFj?Z!z$2mFDF+=uujFo*I3*=6Y)4+I(x70abC>jk?t2v^;TyROO= zezLw|fh<#X2^tVhI~xv4c&iILw|_>|!3)ootZx z5KFPXWMMWH_pwpd%65Vsv(0B|wgt>(>&8lK^;n{=)3bI7!t6G4?l6l>}n$Gn^)Sg3OeoS$bsoR8QtXEIb?l(HXA&b~RrIq+6Pp6(vE zIc;1c)kA_b0!hxJ$l*+d$_$KUXEj{x9D+5{8azPS1zKRo@gC_kj+6G`Z0RW0yI$fZ zu0lN3<-`YECVa`2fPcE)U>`XZw~*iC4RRdLlTYHRbRq6fo8WPvsyLRa@Fl9mE?R~t zeFO|oYmtGCM{QUPn$99&r+gLEn|Yz}%*n^FeBPI(@qR3xcVh>6Pd1E?VBMjOCEypx&%AbPCUn)&zg1ZI+#v9Iz*_FW#!ylDs4nl@rX;MxteCp$(bv6pl@{Dm`Y z2uo$tSUg+7jk9miU;mw@Ai@x!bwzrlL*yKE(QvWL7e-^xF* zpUj_)VVB{vF470gOsm5;n844lnSlOH;g?x8K95~z6WK!6ja6Zh@C{}HCU}))&@5Ji zb>pMhBYqN|(<`wm|uSR#r}-uNCd-JViTNMKOe?i7RNL_!3$(7AK~& zBjPE(R&0nyi0e>Gu@L!)UGXu5MxiMj*d zZZG1F77`2pm!$B=`kyT~80 zM4repcpj^Y9Bd%6u!hK!S3{$DXV`@ni7KNo)E}wQ9#E1hMlN0jOS}~>P8{aW#GhC$X7$7aIgE7HS_qV>9ba zTJf9Y0k0q&yjBnJd_B-3;U|9xynqLV<$RLRnYR^u!P9oK8iJYCfmTaMWKqIpHdOe= zmI@N+-%++nC}vZI>uim%ja?MZu|L9F)>JHGBgGItRBXay#eV#hxSXF8-|&ZGXLMIQ zjCP8T&??azZxPqy^O|NoBN`AT)${p*Cjsc5d0(_^>!cLqf48dlh3U&$vM~m;!2JsNu4*a3J#e?XM zxEs9}_o008B2p+)P#VN+tHfHkn^*-$LGu%PVOfZU*y%jJEZFb_p$q9GOd^$qxdaKz zA%fdMuE5Ve@(`*}UXVZJ6}domks7eK@-W6^I8MZC@E5ElLF5CONftn_Jrv%Poi;@koKA4uS&r7b@YeLPO~FvG~4t99zX}Sgm-3{S^;zfZ`-pDvn}z z#Tu*tF5!=2U3^JYQF`8~xB{zP$=KU2Kt35q*>Kb%J? zo^!K!liv_8@tI;GZy|o+9^x~eBfJIXnk;@*u=3S{8g&vHqsGDj)J^D(1_<=a}<}vrof!>x3WZhq%0ScK#Tl`-+h8kGZ2Qm(-Dm4SGm(uy`I{cw(QIA9RV@B-C3 zJWF*J>gP^E{oEW}Q`Hk^Lp|LZuX7C!lwVW@xQKkD#wXjk6j`QYcV?f}jtI z5M)p~_!#92zFc{eA5*U9=aqx_8)Z)(po-=VRSmhnsxJ3bxpOyFDKo0lSq)VVOHw-7 zG^LUcP>Oss9A_!J@}?ckoOu5{m8vcJm+Uh$Bc0z6Ts^qu?$g@C-Zz z|Af1WBs&0GYKbS2C#W}RfNGN@Sl=)5?|2ip;Eh~Cz>~#acp0{GC+-VR^FLT;KcNVc zhTO;-^c5$g*H}i+unC>TNoXa$g9hQHC<@O(Rblr^WxN7K;>oBfthJSJ4O9crspj}0 zZ-@WpWARwN6L;lTaXI^h&oV^jv)Z8O-HPPXcH|1}13Cc{$VLk4Xy8LB=?sFPwWou~ z4BCM#qOHjs+JelY)u6fXAo>n>qkHjOItXv3mGB&zhi22$Xb-SAJ*J&dHVsCEQ69`N z3S~wl(PpTG{)K$lU{syWMZs)0s>ZgUhHO7-#?sM9RvDjXU2p-LhcQ2d_51;@!oT9m z{0BDh0yt+llDiQfUYRgfmw50H&@*UAw0r>R!6%Zbd;%HGdy*BrH95{Zl5M;`8P9{k zzX~Ufc~$VW7#_j%@pO3B#{sd+=0|W4S_mU`4X%f_fS)r9cSghUOc<>@KvDBF8i(Jb ze%OqHu>ptRKDZ93YWm{oSOQO`3@yhRJP`-tVOYc?F~(D{4ei1Y(G`3Q+BOu2XG2>6 z6_In%P22+=gYml+{@Qt5!XM$Ua0efu$KS!7NxU%$LS2cIN0T&o?HiASo#nAOi8sWl zybyio2~an627Ti_!DlPuce#mQ<-rJ}e&__ciYibV%$gJTbzn3};DNp5V7>T2>V@l55r@)1T%GpB4tY4f zCxaE2z42+;jLyqJc!xX{FO_#eM0E`Bk#FF$@+bUI{(|qz|KWH!78l6Jv6jBaG4wk= zO|RikbR8}OCJY7Zfh)5R+?)A>7QGtxWQk}gJAjTuWN-mket)vj$d|80Rrqog#z&&s zz^N0)PXTw_9f%@cq4(@Jy2>0-=T`&oV{PyT))bFs-Eb>53s+(5V0Z6-*aUwsonFP1 zCSie@u@4I&F>EoJ%+5hOMs~7m2aB zM~DG5|Nou&JGO`aVgK@C_Lx`U&-g0-hCc;dH;41j-YWAJg1$|jB zHjuYsWB34wNJCfyoErR-h4-jEG=|G4jTQW|&F^R@9AGVnd1q^vN{Cky+1~uFHu-on!6Zm5m!C$b+ z5L-^?57}&}jycL@c9RG2^S}vqi7Vh9gJ2{>MwPeVoH4eNm9YM-4&M(~8Tm~37HXWw z2jB!g6p!Ieu!1x6oZUkZZK6hOE9wYw<5n02rAz^He-O^)n{X%e1RqDG*b6Efw%`K% z6~D&WFuT)mB>o6<`5C@~KERsw12={FEAi1VM|{C*g#Ky@cQgk5VlyEE zo`J5gh3E)yV6A4;05#}@+Oirj2R%S(*b`wm>RB=mU^_WsXhP)p1saNsy@?L&VzRXX{7x+PWBi|?w z1!dNF)D;Dl*%rd3w?2J^6{Uh~bCMl7PcE#{}uG8E@PUC;e{wP^)jy!39 zWTfL!iQE?5lbw8({GRuhZ^J#T<%{Hj95l^&FFBU4mlyGDc_uf~-Mk)sz$58>9zhSl zciO}o(1$#jh9OKBB0qW+b)-dT3T=n~r3Y{ZeT(yeGd`aF#vf@0PNjrAqm@V&^&;(A z02#^#kk)J|>B`2Fk*p;d#wwF$Oa}bmDmJpeaBIfUX!Z}GN$#c($^j=LymiO|3K1$v3!0L6_5z&n1MzT-*sC;vl>`3tz$ zTeKs(PY0nVbPak>&%s)F3Hh<3s5#q#V%UFZ2F&CG>@!MX*O7s5N3Fn`&4<~#gSSH) zI6=T1!dLJg`~b}4S3H6L=HIvuedYsE5}$%H_+(fQ7NELl92$svqh+8=z85tIUrLY6 zD2w;NiF_ukIAdYuSq!VnC7ceH{~h=OclaI1UVXx=`7hj$C*WHAC^oTi5QB%}eD)r! z%4U?!2BC+5EbL=vcxTp&+o*#7pf^||9na!uS9SzYrhT+Fph5N6bGm@NqUTvMJc}|VI3LVH}=uN!3u<6u1B%2XfrdR z9I*N=xEAjN6$&e4xO$+T_#7GnD|lbr1djkuaVS2C!|_>I;SU3Hu?w`bx8vr3S~SO} zaZ`K_SHaidcoPrC*KuEb1rLCH;99^pcHvHV8GOPHycDk31@HJ5kNw|!wqiA2g1^J= z(VMW=?gIp6DEfre=nwS32YimF;|1J>J3?#BJ&1~jlGm&d-(~mlBlZU00OaEV*!d@H zEskTI@H^%Q9+4L=1M8&(J0H$BqSjzbBB5$IoIeLu=54$kp9ze=gZO^l8%9TOzJZSi zdw+zl;g8^WijUyCcm&u|e;75TU`OKF7ygWW1pVG0d{x%iI3!u`4nCYEapn| zmVbp&T?Z`g6nvVmz&pWSujeQ65O{haTnGN&a8MPw48Go15)PI63LY%DaU02IN6ASx zoUCTeVSGR(KNCTlsWFM*YlxZ0k&);+>4nCT>flF5qtD=>UBRGrieqsZ_9Y=?7HL7Y zlW~9{OeVQx2>DF9lY4*}93*Dkh5W!KV3^;7&)`P*6fQzn@h9{G$HV75MZX}LaY1jZ zKw%P*BxJ$oVdYqj_TaIo8~zJbhX}=m4x@W$IGTlOq58-hW%3I6&Qa(pKZ3ULNoX*y z1Q^}`)SjP1a{-Av&6O}SAHox9gPQOwJcZTe-&qYF2vvBy!48C=1uzm8^ZT$0WukqY z!>736(Od#vg-0lZEr3;|8Oo0iu;_F_-vYHXjJPv^=Rbg-O5=g0+gsqDi#$b%S?2e2QmI_!@tgel~@%tsDl7FY|O zx$@{WS29goXT#`AcAn<36q?2oXeRgy zfxLoFg_UeGj|Tf%oxvtH+5#og?&vB7?~Xo0@sy&Ev@O0zSL18+4!%ya@O^3|*J(?L zOU9B2I-hi;%gB7XnQWu0;PsWn39U1WC5PA=h!0MZmHZ#@&_<9vZX_z`t2QVN`e!3P zjN0OrNR7v!Z)hsI4bkT%Kqqg4pZpFYD+k1w7%#?!aAg8|ip!B2BFI4yLB^7ecmi2~ zYmn;TJH(@@pt5Ixh${^#P&W8jez=^s#-R|I`9PE=agHlEAx8MiVGtuD6abY(3K9o< z1`hI5cmHIRx-7|bI-^oXT^>4&WU_G+) z`z#n8W`SrPtAN~r%$qTHqyg{GL09uoHiS1~9e5-Q2anFm2D4YJAKTBC0@A;bmCz>a z7Oe)>xjHMARV-1~LJlE-CCiwdg#S;Ly;vJLo3@u9&^GcT+DX1dN6QoGS~-;7khS!y zT${SnUbF?w{gGe+*3zZ)1-%7&2ujuvG6zH8=WozLxCm?jPeBbK2fQ|aj(BHYmCu1O zd>FjZH?XRe@YaApuSIPkj+p}pz;?78VwJ5Bt!zY%aaXhiVzYm6FZ2ZuK?*V&wIYkr zXfg$DB~4HqAec{y4@BOr;n)wo2gI|COhkdg0@O%|1r#a)MF~OJ7j|3(3Iieb--WM{ zG(c3V!TfGPqF|;6k~Ct&k$}VY7w+OU!UlXw7>&;h?ePPM@vjM$@FIZ$c16)10pnGI z8MP7a04v`Xi2diIEE0>-$W*{zqu{7S_sBE8nQY=Qq#xLIBQM0?*hR4Ie?!bM9=B(` zaS-bWt6d#@gr=f4^bV>CS)^Wc13pA8crP{MhBOA>l`o)X@>ulE6@wnR79ml-f%?iH z(E-^79#aRLB+tQx@;3Yp;--i4CWx=P;%%~s2g|QfXL%2*E00FhRR!3k%Xyj0#eL-Z zsE!;BzY9hKWCNNh8__&jgyT0pM83!a<>lPriso2`Ra(Bz+~hOtr|Tbf&@}`+I4AAs z`bzy>PidL7jV4L+XaXFcNq6a2NzY29ZOqU0k@a^y2fpS+R_yZPwdG!XoIH~ME05)b zF5u(o4u~aA^4jbPpA2hH0=vs2`3=6E$HUK29)zYtHev z^2PgECfdS&pb6{)TF4F|&;6zz{{1dC1vD-vfW3=EN=~^izXuj_74Oeyz>FEg z%lT4>iMBxOybpZ$0ax?C_)K<}b!TfJuXmTV z;uY)#Z_QO`A;cjoc`ok+UV%H0=1EM;_pl$Z5~^Jm593&^S(M8ZV$G zE<9=6#D5D*r+GqKVp0dX2Di=8;@hhaaFb$%k(;K3qJTmR!rRadLfeAg_^Ka z=?=>m8nW}kbJ|gep|BH*o&+rFB5|YNNlR)X^XLn*mHq~8C^cN?AuMIy!d*s5I{Qv4 z*aK3BUm}C~G}4zh13w`bu(bnt7hew%+%}xTPh%}0G7SJjTLhljZ`kJ*f@_hcxH=hx zgUKYUA|0?F3C3YWi`_{kTyqxugw5zKASb8rAv6WY!kXR|)^sDfjy%vJl*gN+kI)Y} zd=F0r`}PF->MQTTojiosM`>(0U=W=kn;D7jK$iGFK)p5rHnEXW6vqO*JIJ3vRC^zbXfBRI9dSd{0k=dAz>5t8uR@JmqkI$zL8n%1ATs*w}r7%8*~o6`A@Fl?_h@9fYGv%TUlrRnGv4KWEc^xq3;KR zP4?$!`5U%?A7mZ*dNz$8fq3U3OXu&|B;*8)ZUC%M7kEeffOiMKtPh|@v9NMY!JT;o zcITcDd*>nr_#cd2Kt_K2e-ZBz{sCR$MF?p3P(DvaG9X%Z4unF0);2~lxEY{keb7(v zkql%L8U`7x-LUuW8Yu^>`Ugb_ztC&}LDo!-F9-$bnP5W6f)6eeI$;MOu|>iioDZ3% zOhFA9omymyFc{G5XXFi0z#hLULUS@!Aml%|DoL?7otOA zHxw&|qY0u18Yc##*`SR$O7unTM9Qm+ZpbDG=&taRPZYLuL0HKjl7;*@>BQHO)-b|4 z^0C0)zkpQb=fM;GNwQcjdCGFg4H(gT7$>o;t}v4I6Kd$^$|v}aG^W<0+H%AGLNl<%Hx^jIYc_1fDhK=^&ms+P6hxn zIs$OJPP{Fy&qJ{%55$$g3v3D*^o~3U)#s^*@EfQS;9%`}BB};{g&RMNYC&&=aRJ6! zHtNbBK--U^!0)WVn*eUs6t&}3(IT)a=Xf*poA-y9awbxu)&DzE-W@eVeNil0jN;KY z6aZe&a`1!S0xGH{1Mv{D88QaPa5`iz+e21!hmenV!p_UJLUp_h*tEt7577c47y7Re z9wY9;zr?G!nqnj-koma{IrZhDhAi`x&_WGGkS0X}hzKHrgf2~K0i_5@w%wV3-sd|xbM|I8x#wm#^Z#GFGxk97 zt35(w*z3gS_94*_D^BIYY29M|BL-QwMP<0GjP=@%%UqEm!(xh*va?j8l)NJDh#v)# zoA^ov3#83J$WeBRyZLpV2 zv&2k-;yMxYEEAaK0Q8>k&D;3R_whb9gJ$$Peyci-MU_Z4HG%J|!+)$hQ@q3;8Ut+juadM=$55tLX1#u7M(R7zRxEU-QuIg_ zr0XhZzE}56y1HU!sKe$fb;hhz%B)fq=_l2WV)P1Xf^LLxagtZ7i07saaeBy zs@W>yc#n7&TFN+nNABQMnaxM!KkUkz91l-EV6EpkYXeuXW^%GMgMYHp*|xvtm+X;T z!mh>7t#f*{m8|<%jxKL)RtM!IHCpad>tqWZf*w%YfU0ab0F1Bz6}k=TTs%IxOUU75aYJ(t zJ5&}zw|l{)7~6C=mgx%R@l7a?Ib0fi`4(^G*+8;wc@r`@UvnECitag(KL^Im;3VFQ zyv{0QTsCt_&SeYzw-CGH_rY~3H#Y*I~a(--IJjdOiw3IGimZf+hT)AKXe!0u$t%`|Rl=Af%@ z2V2+%C2J!0M5pg!KEd~$xsz$m-OGhB-spm3=moeEeP}$br+#!4j^7<{tKx9&-VoKPAw~*(mvr$IUG9oGjt+Mext1Tr z9`i&zG9=I8IL!tg>s;x#hZN004&yJ&SM`f?6LtxC<`vrFBpbnL}9%Ch*v>F_fTIj&{Mji zsiKebRdtYes3%ZFpYsCjKeSqPz>L^ocBqHuG-k;$)s!}?=`>p%qy8AJ)erQxQdCCO zL)@&rc%5f#k@Jf=cXNrVoSDBd&U z#Za?RtbjMQ7LS|E`#850m(j7$W3{Ra<}BSezmmpr0lGmAu$JFM%&ZJxk;UW}>EOPr z=qk;F+BlXlZ`uux-5i=iT3d;nxUNc=!Uz^I1;dyN+NFh@_oC0xvcU>7;Y}~5 z$#Nb%*zUAK{%vN;)n>7rXO_rM%u!j*Jd|%i38)Tk76ZTSFMce}@Ch*wdfOmgFH$&7 z{FjG_wNO5{z#AIJ1>iL;1}-myWM4LviTPmCiKZ|QFn>dlM()BK)f3HjecogN_ZxU( zO}VBR$}Pn}E+_&(ymNI=>_FLsTIobe)M+$BXVEEL7+%(k;$yx`T{(l=0wH%pQZSL{ z0Kpqnk;AAWbD`>YL3MeLr*UP>|EJJx?(1T}*Hw%Sr=$?{=&H!iwFFa0=96X;-!lui zCY|D56leYe?A3%`gSwQ6u09@JXBC*resrcx)W6AK1Kr>Vy^UT{2Z};5^o?6!8z-<5 z;ufxnYEa57I}};y!;Ou0eZ$ z0%z_hH^3*-N_@uE#14K%e2<;0FK~UJFCD z4Mn9GLf^uhUe0T1E6>BfO)b2CZ8_6S!1I}SucmN)`j|U`1$<1~cmQ?hHZ)H^Guzc< z(@cG6lGI4^ow{y9VC|*#r)1O=I-t7Jc*Ulgx@f+4@0eb0(6n}6pj5XuZFIZRGdGPo zsU@^h9ig)-n@Ylu@22lj54gDR=-O042TiQrXKtza@PSgyS`}x0gWq#c_2pkwBTiRu z@_48|W7RV~ScP?GW%Nkp;T3poC3fi8hY?asxR!p#?R5iFN)I>J;3tLEPLrU^Q981) ztx&b{cn&n$Le>p#hkoDK8qP0SebN61a|x>t*T8WXYY{K7?(q*+eRI>AV9H^Y>Hc;t z>S2FHP3`kk-HsCuR+PMF4Hbv1X}E84rnn`ih-GrD7$AFz8nUejiaz2TwEE-t+6f2m zkaz$cH(&UqPgatS91c}yD=^*_xdYnIe9;p3VD_}y1B><(JHZ6brYT6{(zlnF2sTc)UFxn6BU!sCb>r?1Py z`U=*5*#-Z3nH&LkC5_w5S)2f0q8XAFLu6f~FlU-aGGr=R$z?sTg&BaYbjDS z>*Qnk2eNxbtzNRAC1g;Z7Z2qz+y|8*j>z#?Wx2n&A-iHEitBQK_yxM_Hxhmoko-RR zfm{iNeu#Y4Y9p6e<)pTrh?e$QvCLi}p5v~sR~=i_bS`5L?EM&rsETuhN;}_B$X-dS z?djA3Ls`pcur(dZ-B=QGH#HUykfit%jP)knhVN35yNW(~fS9EQh$HSU5s5w%?W3E; z^++|bF!GE(iP)lXWPbf`_XueDegp?>Mo$s?o!O=jg;uFpc?K}dJ)g(M^h;)+MK2%**-M- z4mFAnqq~u{v?sEOPDM7;xyU`*7^x^`N2-e5kxIfFeNA+UT4G=H5xwUY6hXH-_E1C; zO)ID|m*@ei*F>}^d?J=N(0PgTlxn$kcg5j)H$AvxNcTG>sgh+PTSR13WFefkDT!+q9k zw8N@P+pTtV2cxk4Hr2I_8IIKAR{OTe2A@>+a#P(&GX0#EX1G(={KxSapL3MA+WWYg zy@7XH1GtIRk5|emd`L{;YqSZ-_bkwN7T?mF_?FtpS?)fb9zD;=krUiIyoN`FGI)3J z6i4$Fcg-(guH@x&m%KB4KX)(B%{|18b9Zu)+*I6=(iF!{xd}$s-1c~_6X)bs;r@AA zKhC?Llk=DA8~LMjm0*fa4Ytu|f)#YxP`pkKIr?kMzT4{CLi-JP2`&H295fR@dv0OWY6Th?}AL@=-`w#l!WjR^c($;P4r1WB3Kzj?}YzMqaT`M{ZifqF-Be+^SYV zwG4bDM&8w_@SV@0Ml_^>U=m$LHa9?C;&pKIDt1roKX*<&az0e&JhAGS_fPk`m;>%y z-!8YU|5sP}&${aaS#G=7`|jD;Mk*9LUi}%nNBtE0P;HGZqrZ$@teeEv=A6Jn?iF~> z%lv8PwlC9sfRP@v$E?I>yv8%uoJ1nI2-X5xY1cDpHgXVlNi)qp#slph*gZXln<42u z%wC|++cWh*XN(RywRI!URn^TiNu_w|tC_gAo1S>p!<(iyc)_&21$m+O5|8rkG9A6s zskpbcxZ^o1R(euoz*E3VaMoEP?5g$%Ynk0x=Gq0sH0Pq}>`6n`wvfK+z39%5IUFtH zTNBytdq3RCUnX?H-zr!=urPl};6~o4z<|8ofs%QZ0>9+m^{>ud=ii)L-G3o>u&-#| z(wO#nQSXGjH1DIlyPo9yVV;xuRXvr0e>z_WhdK{}u}-5twwzsBxIA&lp-FGe0$e$27=wB3W6?h?h bF0eaPE4F!PO6>2!oY*D7PH{tnyW{=`Zj*rx diff --git a/3rdparty/chromaprint/tests/main.cpp b/3rdparty/chromaprint/tests/main.cpp deleted file mode 100644 index 7ed0f518e..000000000 --- a/3rdparty/chromaprint/tests/main.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include - -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - diff --git a/3rdparty/chromaprint/tests/test_api.cpp b/3rdparty/chromaprint/tests/test_api.cpp deleted file mode 100644 index 0fb47f9bc..000000000 --- a/3rdparty/chromaprint/tests/test_api.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include -#include -#include -#include -#include -#include "chromaprint.h" - -using namespace std; - -TEST(API, Test2SilenceFp) -{ - short zeroes[1024]; - fill(zeroes, zeroes + 1024, 0); - - ChromaprintContext *ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_TEST2); - chromaprint_start(ctx, 44100, 1); - for (int i = 0; i < 130; i++) { - chromaprint_feed(ctx, zeroes, 1024); - } - - char *fp; - - chromaprint_finish(ctx); - chromaprint_get_fingerprint(ctx, &fp); - - ASSERT_EQ(18, strlen(fp)); - EXPECT_EQ(string("AQAAA0mUaEkSRZEGAA"), string(fp)); -} - -TEST(API, Test2SilenceRawFp) -{ - short zeroes[1024]; - fill(zeroes, zeroes + 1024, 0); - - ChromaprintContext *ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_TEST2); - chromaprint_start(ctx, 44100, 1); - for (int i = 0; i < 130; i++) { - chromaprint_feed(ctx, zeroes, 1024); - } - - int32_t *fp; - int length; - - chromaprint_finish(ctx); - chromaprint_get_raw_fingerprint(ctx, (void **)&fp, &length); - - ASSERT_EQ(3, length); - EXPECT_EQ(627964279, fp[0]); - EXPECT_EQ(627964279, fp[1]); - EXPECT_EQ(627964279, fp[2]); -} - -TEST(API, TestEncodeFingerprint) -{ - int32_t fingerprint[] = { 1, 0 }; - char expected[] = { 55, 0, 0, 2, 65, 0 }; - - char *encoded; - int encoded_size; - chromaprint_encode_fingerprint(fingerprint, 2, 55, (void **)&encoded, &encoded_size, 0); - - ASSERT_EQ(6, encoded_size); - for (int i = 0; i < encoded_size; i++) { - ASSERT_EQ(expected[i], encoded[i]) << "Different at " << i; - } - - free(encoded); -} - -TEST(API, TestEncodeFingerprintBase64) -{ - int32_t fingerprint[] = { 1, 0 }; - char expected[] = "NwAAAkEA"; - - char *encoded; - int encoded_size; - chromaprint_encode_fingerprint(fingerprint, 2, 55, (void **)&encoded, &encoded_size, 1); - - ASSERT_EQ(8, encoded_size); - ASSERT_STREQ(expected, encoded); - - free(encoded); -} - -TEST(API, TestDecodeFingerprint) -{ - char data[] = { 55, 0, 0, 2, 65, 0 }; - - int32_t *fingerprint; - int size; - int algorithm; - chromaprint_decode_fingerprint(data, 6, (void **)&fingerprint, &size, &algorithm, 0); - - ASSERT_EQ(2, size); - ASSERT_EQ(55, algorithm); - ASSERT_EQ(1, fingerprint[0]); - ASSERT_EQ(0, fingerprint[1]); -} - diff --git a/3rdparty/chromaprint/tests/test_audio_processor.cpp b/3rdparty/chromaprint/tests/test_audio_processor.cpp deleted file mode 100644 index 66f271aa8..000000000 --- a/3rdparty/chromaprint/tests/test_audio_processor.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include -#include -#include -#include -#include -#include "test_utils.h" -#include "audio_processor.h" -#include "audio_buffer.h" -#include "utils.h" - -using namespace std; -using namespace Chromaprint; - -TEST(AudioProcessor, Accessors) -{ - vector data = LoadAudioFile("data/test_mono_44100.raw"); - - boost::scoped_ptr buffer(new AudioBuffer()); - boost::scoped_ptr buffer2(new AudioBuffer()); - boost::scoped_ptr processor(new AudioProcessor(44100, buffer.get())); - - EXPECT_EQ(44100, processor->target_sample_rate()); - EXPECT_EQ(buffer.get(), processor->consumer()); - - processor->set_target_sample_rate(11025); - EXPECT_EQ(11025, processor->target_sample_rate()); - - processor->set_consumer(buffer2.get()); - EXPECT_EQ(buffer2.get(), processor->consumer()); -} - -TEST(AudioProcessor, PassThrough) -{ - vector data = LoadAudioFile("data/test_mono_44100.raw"); - - boost::scoped_ptr buffer(new AudioBuffer()); - boost::scoped_ptr processor(new AudioProcessor(44100, buffer.get())); - processor->Reset(44100, 1); - processor->Consume(&data[0], data.size()); - processor->Flush(); - - ASSERT_EQ(data.size(), buffer->data().size()); - for (size_t i = 0; i < data.size(); i++) { - ASSERT_EQ(data[i], buffer->data()[i]) << "Signals differ at index " << i; - } -} - -TEST(AudioProcessor, StereoToMono) -{ - vector data1 = LoadAudioFile("data/test_stereo_44100.raw"); - vector data2 = LoadAudioFile("data/test_mono_44100.raw"); - - boost::scoped_ptr buffer(new AudioBuffer()); - boost::scoped_ptr processor(new AudioProcessor(44100, buffer.get())); - processor->Reset(44100, 2); - processor->Consume(&data1[0], data1.size()); - processor->Flush(); - - ASSERT_EQ(data2.size(), buffer->data().size()); - for (size_t i = 0; i < data2.size(); i++) { - ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i; - } -} - -TEST(AudioProcessor, ResampleMono) -{ - vector data1 = LoadAudioFile("data/test_mono_44100.raw"); - vector data2 = LoadAudioFile("data/test_mono_11025.raw"); - - boost::scoped_ptr buffer(new AudioBuffer()); - boost::scoped_ptr processor(new AudioProcessor(11025, buffer.get())); - processor->Reset(44100, 1); - processor->Consume(&data1[0], data1.size()); - processor->Flush(); - - ASSERT_EQ(data2.size(), buffer->data().size()); - for (size_t i = 0; i < data2.size(); i++) { - ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i; - } -} - -TEST(AudioProcessor, ResampleMonoNonInteger) -{ - vector data1 = LoadAudioFile("data/test_mono_44100.raw"); - vector data2 = LoadAudioFile("data/test_mono_8000.raw"); - - boost::scoped_ptr buffer(new AudioBuffer()); - boost::scoped_ptr processor(new AudioProcessor(8000, buffer.get())); - processor->Reset(44100, 1); - processor->Consume(&data1[0], data1.size()); - processor->Flush(); - - ASSERT_EQ(data2.size(), buffer->data().size()); - for (size_t i = 0; i < data2.size(); i++) { - ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i; - } -} - -TEST(AudioProcessor, StereoToMonoAndResample) -{ - vector data1 = LoadAudioFile("data/test_stereo_44100.raw"); - vector data2 = LoadAudioFile("data/test_mono_11025.raw"); - - boost::scoped_ptr buffer(new AudioBuffer()); - boost::scoped_ptr processor(new AudioProcessor(11025, buffer.get())); - processor->Reset(44100, 2); - processor->Consume(&data1[0], data1.size()); - processor->Flush(); - - ASSERT_EQ(data2.size(), buffer->data().size()); - for (size_t i = 0; i < data2.size(); i++) { - ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i; - } -} diff --git a/3rdparty/chromaprint/tests/test_base64.cpp b/3rdparty/chromaprint/tests/test_base64.cpp deleted file mode 100644 index 59d0d55a8..000000000 --- a/3rdparty/chromaprint/tests/test_base64.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include "base64.h" -#include "test_utils.h" - -using namespace std; -using namespace Chromaprint; - -TEST(Base64, Base64Encode) -{ - ASSERT_EQ("eA", Base64Encode("x")); - ASSERT_EQ("eHg", Base64Encode("xx")); - ASSERT_EQ("eHh4", Base64Encode("xxx")); - ASSERT_EQ("eHh4eA", Base64Encode("xxxx")); - ASSERT_EQ("eHh4eHg", Base64Encode("xxxxx")); - ASSERT_EQ("eHh4eHh4", Base64Encode("xxxxxx")); - ASSERT_EQ("_-4", Base64Encode("\xff\xee")); -} - -TEST(Base64, Base64Decode) -{ - ASSERT_EQ("x", Base64Decode("eA")); - ASSERT_EQ("xx", Base64Decode("eHg")); - ASSERT_EQ("xxx", Base64Decode("eHh4")); - ASSERT_EQ("xxxx", Base64Decode("eHh4eA")); - ASSERT_EQ("xxxxx", Base64Decode("eHh4eHg")); - ASSERT_EQ("xxxxxx", Base64Decode("eHh4eHh4")); - ASSERT_EQ("\xff\xee", Base64Decode("_-4")); -} - -TEST(Base64, Base64EncodeLong) -{ - char original[] = { - 1, 0, 1, 207, 17, 181, 36, 18, 19, 37, 65, 15, 31, 197, 149, 161, 63, 33, 22, - 60, 141, 27, 202, 35, 184, 47, 254, 227, 135, 135, 11, 58, 139, 208, 65, 127, - 52, 167, 241, 31, 99, 182, 25, 159, 96, 70, 71, 160, 251, 168, 75, 132, 185, - 112, 230, 193, 133, 252, 42, 126, 66, 91, 121, 60, 135, 79, 24, 185, 210, 28, - 199, 133, 255, 240, 113, 101, 67, 199, 23, 225, 181, 160, 121, 140, 67, 123, - 161, 229, 184, 137, 30, 205, 135, 119, 70, 94, 252, 71, 120, 150 - }; - char encoded[] = "AQABzxG1JBITJUEPH8WVoT8hFjyNG8ojuC_-44eHCzqL0EF_NKfxH2O2GZ9gRkeg-6hLhLlw5sGF_Cp-Qlt5PIdPGLnSHMeF__BxZUPHF-G1oHmMQ3uh5biJHs2Hd0Ze_Ed4lg"; - ASSERT_EQ(encoded, Base64Encode(string(original, NELEMS(original)))); -} - -TEST(Base64, Base64DecodeLong) -{ - char original[] = { - 1, 0, 1, 207, 17, 181, 36, 18, 19, 37, 65, 15, 31, 197, 149, 161, 63, 33, 22, - 60, 141, 27, 202, 35, 184, 47, 254, 227, 135, 135, 11, 58, 139, 208, 65, 127, - 52, 167, 241, 31, 99, 182, 25, 159, 96, 70, 71, 160, 251, 168, 75, 132, 185, - 112, 230, 193, 133, 252, 42, 126, 66, 91, 121, 60, 135, 79, 24, 185, 210, 28, - 199, 133, 255, 240, 113, 101, 67, 199, 23, 225, 181, 160, 121, 140, 67, 123, - 161, 229, 184, 137, 30, 205, 135, 119, 70, 94, 252, 71, 120, 150 - }; - char encoded[] = "AQABzxG1JBITJUEPH8WVoT8hFjyNG8ojuC_-44eHCzqL0EF_NKfxH2O2GZ9gRkeg-6hLhLlw5sGF_Cp-Qlt5PIdPGLnSHMeF__BxZUPHF-G1oHmMQ3uh5biJHs2Hd0Ze_Ed4lg"; - ASSERT_EQ(string(original, NELEMS(original)), Base64Decode(string(encoded))); -} diff --git a/3rdparty/chromaprint/tests/test_bit_string_reader.cpp b/3rdparty/chromaprint/tests/test_bit_string_reader.cpp deleted file mode 100644 index 9f358e915..000000000 --- a/3rdparty/chromaprint/tests/test_bit_string_reader.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -#include -#include -#include -#include "image.h" -#include "classifier.h" -#include "bit_string_reader.h" -#include "utils.h" -#include "test_utils.h" - -using namespace std; -using namespace Chromaprint; - -TEST(BitStringReader, OneByte) -{ - char data[] = { -28 }; - BitStringReader reader(string(data, 1)); - - ASSERT_EQ(0, reader.Read(2)); - ASSERT_EQ(1, reader.Read(2)); - ASSERT_EQ(2, reader.Read(2)); - ASSERT_EQ(3, reader.Read(2)); -} - -TEST(BitStringReader, TwoBytesIncomplete) -{ - char data[] = { -28, 1 }; - BitStringReader reader(string(data, 2)); - - ASSERT_EQ(0, reader.Read(2)); - ASSERT_EQ(1, reader.Read(2)); - ASSERT_EQ(2, reader.Read(2)); - ASSERT_EQ(3, reader.Read(2)); - ASSERT_EQ(1, reader.Read(2)); -} - -TEST(BitStringReader, TwoBytesSplit) -{ - char data[] = { -120, 6 }; - BitStringReader reader(string(data, 2)); - - ASSERT_EQ(0, reader.Read(3)); - ASSERT_EQ(1, reader.Read(3)); - ASSERT_EQ(2, reader.Read(3)); - ASSERT_EQ(3, reader.Read(3)); -} diff --git a/3rdparty/chromaprint/tests/test_bit_string_writer.cpp b/3rdparty/chromaprint/tests/test_bit_string_writer.cpp deleted file mode 100644 index 4a54e0534..000000000 --- a/3rdparty/chromaprint/tests/test_bit_string_writer.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include -#include -#include -#include "image.h" -#include "classifier.h" -#include "bit_string_writer.h" -#include "utils.h" -#include "test_utils.h" - -using namespace std; -using namespace Chromaprint; - -TEST(BitStringWriter, OneByte) -{ - BitStringWriter writer; - writer.Write(0, 2); - writer.Write(1, 2); - writer.Write(2, 2); - writer.Write(3, 2); - writer.Flush(); - - char expected[] = { -28 }; - CheckString(writer.value(), expected, sizeof(expected)/sizeof(expected[0])); -} - -TEST(BitStringWriter, TwoBytesIncomplete) -{ - BitStringWriter writer; - writer.Write(0, 2); - writer.Write(1, 2); - writer.Write(2, 2); - writer.Write(3, 2); - writer.Write(1, 2); - writer.Flush(); - - char expected[] = { -28, 1 }; - CheckString(writer.value(), expected, sizeof(expected)/sizeof(expected[0])); -} - -TEST(BitStringWriter, TwoBytesSplit) -{ - BitStringWriter writer; - writer.Write(0, 3); - writer.Write(1, 3); - writer.Write(2, 3); - writer.Write(3, 3); - writer.Flush(); - - char expected[] = { -120, 6 }; - CheckString(writer.value(), expected, sizeof(expected)/sizeof(expected[0])); -} diff --git a/3rdparty/chromaprint/tests/test_chroma.cpp b/3rdparty/chromaprint/tests/test_chroma.cpp deleted file mode 100644 index 6a927a13d..000000000 --- a/3rdparty/chromaprint/tests/test_chroma.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include -#include -#include -#include "fft_frame.h" -#include "chroma.h" - -using namespace std; -using namespace Chromaprint; - -class FeatureVectorBuffer : public FeatureVectorConsumer -{ -public: - void Consume(std::vector &features) - { - m_features = features; - } - - std::vector m_features; -}; - -TEST(Chroma, NormalA) { - FeatureVectorBuffer buffer; - Chroma chroma(10, 510, 256, 1000, &buffer); - FFTFrame frame(128); - std::fill(frame.data(), frame.data() + frame.size(), 0.0); - frame.data()[113] = 1.0; - chroma.Consume(frame); - ASSERT_EQ(12, buffer.m_features.size()); - double expected_features[12] = { - 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - }; - for (int i = 0; i < 12; i++) { - EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i; - } -} - -TEST(Chroma, NormalGSharp) { - FeatureVectorBuffer buffer; - Chroma chroma(10, 510, 256, 1000, &buffer); - FFTFrame frame(128); - std::fill(frame.data(), frame.data() + frame.size(), 0.0); - frame.data()[112] = 1.0; - chroma.Consume(frame); - ASSERT_EQ(12, buffer.m_features.size()); - double expected_features[12] = { - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, - }; - for (int i = 0; i < 12; i++) { - EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i; - } -} - -TEST(Chroma, NormalB) { - FeatureVectorBuffer buffer; - Chroma chroma(10, 510, 256, 1000, &buffer); - FFTFrame frame(128); - std::fill(frame.data(), frame.data() + frame.size(), 0.0); - frame.data()[64] = 1.0; // 250 Hz - chroma.Consume(frame); - ASSERT_EQ(12, buffer.m_features.size()); - double expected_features[12] = { - 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - }; - for (int i = 0; i < 12; i++) { - EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i; - } -} - -TEST(Chroma, InterpolatedB) { - FeatureVectorBuffer buffer; - Chroma chroma(10, 510, 256, 1000, &buffer); - chroma.set_interpolate(true); - FFTFrame frame(128); - std::fill(frame.data(), frame.data() + frame.size(), 0.0); - frame.data()[64] = 1.0; - chroma.Consume(frame); - ASSERT_EQ(12, buffer.m_features.size()); - double expected_features[12] = { - 0.0, 0.286905, 0.713095, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - }; - for (int i = 0; i < 12; i++) { - EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i; - } -} - -TEST(Chroma, InterpolatedA) { - FeatureVectorBuffer buffer; - Chroma chroma(10, 510, 256, 1000, &buffer); - chroma.set_interpolate(true); - FFTFrame frame(128); - std::fill(frame.data(), frame.data() + frame.size(), 0.0); - frame.data()[113] = 1.0; - chroma.Consume(frame); - ASSERT_EQ(12, buffer.m_features.size()); - double expected_features[12] = { - 0.555242, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.444758, - }; - for (int i = 0; i < 12; i++) { - EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i; - } -} - -TEST(Chroma, InterpolatedGSharp) { - FeatureVectorBuffer buffer; - Chroma chroma(10, 510, 256, 1000, &buffer); - chroma.set_interpolate(true); - FFTFrame frame(128); - std::fill(frame.data(), frame.data() + frame.size(), 0.0); - frame.data()[112] = 1.0; - chroma.Consume(frame); - ASSERT_EQ(12, buffer.m_features.size()); - double expected_features[12] = { - 0.401354, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.598646, - }; - for (int i = 0; i < 12; i++) { - EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i; - } -} - diff --git a/3rdparty/chromaprint/tests/test_chroma_filter.cpp b/3rdparty/chromaprint/tests/test_chroma_filter.cpp deleted file mode 100644 index b99959dcc..000000000 --- a/3rdparty/chromaprint/tests/test_chroma_filter.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include "image.h" -#include "image_builder.h" -#include "chroma_filter.h" - -using namespace std; -using namespace Chromaprint; - -TEST(ChromaFilter, Blur2) { - double coefficients[] = { 0.5, 0.5 }; - Image image(12); - ImageBuilder builder(&image); - ChromaFilter filter(coefficients, 2, &builder); - double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - std::vector v1(d1, d1 + 12); - std::vector v2(d2, d2 + 12); - std::vector v3(d3, d3 + 12); - filter.Consume(v1); - filter.Consume(v2); - filter.Consume(v3); - ASSERT_EQ(2, image.NumRows()); - EXPECT_EQ(0.5, image[0][0]); - EXPECT_EQ(1.5, image[1][0]); - EXPECT_EQ(5.5, image[0][1]); - EXPECT_EQ(6.5, image[1][1]); -} - -TEST(ChromaFilter, Blur3) { - double coefficients[] = { 0.5, 0.7, 0.5 }; - Image image(12); - ImageBuilder builder(&image); - ChromaFilter filter(coefficients, 3, &builder); - double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - double d4[] = { 3.0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - std::vector v1(d1, d1 + 12); - std::vector v2(d2, d2 + 12); - std::vector v3(d3, d3 + 12); - std::vector v4(d4, d4 + 12); - filter.Consume(v1); - filter.Consume(v2); - filter.Consume(v3); - filter.Consume(v4); - ASSERT_EQ(2, image.NumRows()); - EXPECT_FLOAT_EQ(1.7, image[0][0]); - EXPECT_FLOAT_EQ(3.399999999999999, image[1][0]); - EXPECT_FLOAT_EQ(10.199999999999999, image[0][1]); - EXPECT_FLOAT_EQ(11.899999999999999, image[1][1]); -} - -TEST(ChromaFilter, Diff) { - double coefficients[] = { 1.0, -1.0 }; - Image image(12); - ImageBuilder builder(&image); - ChromaFilter filter(coefficients, 2, &builder); - double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - std::vector v1(d1, d1 + 12); - std::vector v2(d2, d2 + 12); - std::vector v3(d3, d3 + 12); - filter.Consume(v1); - filter.Consume(v2); - filter.Consume(v3); - ASSERT_EQ(2, image.NumRows()); - EXPECT_EQ(-1.0, image[0][0]); - EXPECT_EQ(-1.0, image[1][0]); - EXPECT_EQ(-1.0, image[0][1]); - EXPECT_EQ(-1.0, image[1][1]); -} - diff --git a/3rdparty/chromaprint/tests/test_chroma_resampler.cpp b/3rdparty/chromaprint/tests/test_chroma_resampler.cpp deleted file mode 100644 index f7eeb833e..000000000 --- a/3rdparty/chromaprint/tests/test_chroma_resampler.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include "image.h" -#include "image_builder.h" -#include "chroma_resampler.h" - -using namespace std; -using namespace Chromaprint; - -TEST(ChromaResampler, Test1) { - Image image(12); - ImageBuilder builder(&image); - ChromaResampler resampler(2, &builder); - double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - std::vector v1(d1, d1 + 12); - std::vector v2(d2, d2 + 12); - std::vector v3(d3, d3 + 12); - resampler.Consume(v1); - resampler.Consume(v2); - resampler.Consume(v3); - ASSERT_EQ(1, image.NumRows()); - EXPECT_EQ(0.5, image[0][0]); - EXPECT_EQ(5.5, image[0][1]); -} - -TEST(ChromaResampler, Test2) { - Image image(12); - ImageBuilder builder(&image); - ChromaResampler resampler(2, &builder); - double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - double d4[] = { 3.0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; - std::vector v1(d1, d1 + 12); - std::vector v2(d2, d2 + 12); - std::vector v3(d3, d3 + 12); - std::vector v4(d4, d4 + 12); - resampler.Consume(v1); - resampler.Consume(v2); - resampler.Consume(v3); - resampler.Consume(v4); - ASSERT_EQ(2, image.NumRows()); - EXPECT_EQ(0.5, image[0][0]); - EXPECT_EQ(5.5, image[0][1]); - EXPECT_EQ(2.5, image[1][0]); - EXPECT_EQ(7.5, image[1][1]); -} diff --git a/3rdparty/chromaprint/tests/test_chromaprint.cpp b/3rdparty/chromaprint/tests/test_chromaprint.cpp deleted file mode 100644 index 26fe7120b..000000000 --- a/3rdparty/chromaprint/tests/test_chromaprint.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include -#include -#include -#include -#include "audio_processor.h" -#include "test_utils.h" -#include "audio_processor.h" -#include "chroma.h" -#include "chroma_normalizer.h" -#include "chroma_resampler.h" -#include "fft.h" -#include "audio_processor.h" -#include "image.h" -#include "image_builder.h" -#include "utils.h" - -using namespace std; -using namespace Chromaprint; - -static const int SAMPLE_RATE = 11025; -static const int FRAME_SIZE = 4096; -static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720; -static const int MIN_FREQ = 28; -static const int MAX_FREQ = 3520; -static const int MAX_FILTER_WIDTH = 20; - -TEST(Chromaprint, BasicImage) -{ - vector data = LoadAudioFile("data/test_stereo_44100.raw"); - - Chromaprint::Image image(12); - Chromaprint::ImageBuilder image_builder(&image); - Chromaprint::ChromaNormalizer chroma_normalizer(&image_builder); - Chromaprint::Chroma chroma(MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &chroma_normalizer); - Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, &chroma); - Chromaprint::AudioProcessor processor(SAMPLE_RATE, &fft); - - processor.Reset(44100, 2); - processor.Consume(&data[0], data.size()); - processor.Flush(); - - double chromagram[][12] = { - { 0.155444, 0.268618, 0.474445, 0.159887, 0.1761, 0.423511, 0.178933, 0.34433, 0.360958, 0.30421, 0.200217, 0.17072 }, - { 0.159809, 0.238675, 0.286526, 0.166119, 0.225144, 0.449236, 0.162444, 0.371875, 0.259626, 0.483961, 0.24491, 0.17034 }, - { 0.156518, 0.271503, 0.256073, 0.152689, 0.174664, 0.52585, 0.141517, 0.253695, 0.293199, 0.332114, 0.442906, 0.170459 }, - { 0.154183, 0.38592, 0.497451, 0.203884, 0.362608, 0.355691, 0.125349, 0.146766, 0.315143, 0.318133, 0.172547, 0.112769 }, - { 0.201289, 0.42033, 0.509467, 0.259247, 0.322772, 0.325837, 0.140072, 0.177756, 0.320356, 0.228176, 0.148994, 0.132588 }, - { 0.187921, 0.302804, 0.46976, 0.302809, 0.183035, 0.228691, 0.206216, 0.35174, 0.308208, 0.233234, 0.316017, 0.243563 }, - { 0.213539, 0.240346, 0.308664, 0.250704, 0.204879, 0.365022, 0.241966, 0.312579, 0.361886, 0.277293, 0.338944, 0.290351 }, - { 0.227784, 0.252841, 0.295752, 0.265796, 0.227973, 0.451155, 0.219418, 0.272508, 0.376082, 0.312717, 0.285395, 0.165745 }, - { 0.168662, 0.180795, 0.264397, 0.225101, 0.562332, 0.33243, 0.236684, 0.199847, 0.409727, 0.247569, 0.21153, 0.147286 }, - { 0.0491864, 0.0503369, 0.130942, 0.0505802, 0.0694409, 0.0303877, 0.0389852, 0.674067, 0.712933, 0.05762, 0.0245158, 0.0389336 }, - { 0.0814379, 0.0312366, 0.240546, 0.134609, 0.063374, 0.0466124, 0.0752175, 0.657041, 0.680085, 0.0720311, 0.0249404, 0.0673359 }, - { 0.139331, 0.0173442, 0.49035, 0.287237, 0.0453947, 0.0873279, 0.15423, 0.447475, 0.621502, 0.127166, 0.0355933, 0.141163 }, - { 0.115417, 0.0132515, 0.356601, 0.245902, 0.0283943, 0.0588233, 0.117077, 0.499376, 0.715366, 0.100398, 0.0281382, 0.0943482 }, - { 0.047297, 0.0065354, 0.181074, 0.121455, 0.0135504, 0.030693, 0.0613105, 0.631705, 0.73548, 0.0550565, 0.0128093, 0.0460393 }, - }; - - ASSERT_EQ(14, image.NumRows()) << "Numbers of rows doesn't match"; - for (int y = 0; y < 14; y++) { - for (int x = 0; x < 12; x++) { - EXPECT_NEAR(chromagram[y][x], image[y][x], 1e-5) - << "Image not equal at (" << x << ", " << y << ")"; - } - } -} diff --git a/3rdparty/chromaprint/tests/test_combined_buffer.cpp b/3rdparty/chromaprint/tests/test_combined_buffer.cpp deleted file mode 100644 index cfc17bd73..000000000 --- a/3rdparty/chromaprint/tests/test_combined_buffer.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include -#include -#include "combined_buffer.h" - -using namespace std; -using namespace Chromaprint; - -TEST(CombinedBuffer, Size) { - short buffer1[] = { 1, 2, 3, 4, 5 }; - short buffer2[] = { 6, 7, 8 }; - CombinedBuffer buffer(buffer1, 5, buffer2, 3); - EXPECT_EQ(8, buffer.Size()); - buffer.Shift(1); - EXPECT_EQ(7, buffer.Size()); -} - -TEST(CombinedBuffer, AccessElements) { - short buffer1[] = { 1, 2, 3, 4, 5 }; - short buffer2[] = { 6, 7, 8 }; - CombinedBuffer buffer(buffer1, 5, buffer2, 3); - for (int i = 0; i < 8; i++) { - EXPECT_EQ(1 + i, buffer[i]); - } - buffer.Shift(1); - for (int i = 0; i < 7; i++) { - EXPECT_EQ(2 + i, buffer[i]); - } - buffer.Shift(5); - for (int i = 0; i < 2; i++) { - EXPECT_EQ(7 + i, buffer[i]); - } -} - -TEST(CombinedBuffer, AccessElementsViaIterator) { - short buffer1[] = { 1, 2, 3, 4, 5 }; - short buffer2[] = { 6, 7, 8 }; - CombinedBuffer buffer(buffer1, 5, buffer2, 3); - CombinedBuffer::Iterator iter = buffer.Begin(); - for (int i = 0; i < 8; i++) { - EXPECT_EQ(1 + i, *iter); - ++iter; - } - EXPECT_TRUE(buffer.End() == iter); -} - -TEST(CombinedBuffer, AccessElementsViaIteratorAfterShift) { - short buffer1[] = { 1, 2, 3, 4, 5 }; - short buffer2[] = { 6, 7, 8 }; - CombinedBuffer buffer(buffer1, 5, buffer2, 3); - buffer.Shift(6); - CombinedBuffer::Iterator iter = buffer.Begin(); - for (int i = 0; i < 2; i++) { - EXPECT_EQ(7 + i, *iter); - ++iter; - } - EXPECT_TRUE(buffer.End() == iter); -} - -TEST(CombinedBuffer, CopyUsingStlAlgorithms) { - short buffer1[] = { 1, 2, 3, 4, 5 }; - short buffer2[] = { 6, 7, 8 }; - short tmp[10]; - CombinedBuffer buffer(buffer1, 5, buffer2, 3); - fill(tmp, tmp + 10, 0); - for (int i = 0; i < 10; i++) { - EXPECT_EQ(0, tmp[i]); - } - copy(buffer.Begin(), buffer.End(), tmp); - for (int i = 0; i < 8; i++) { - EXPECT_EQ(1 + i, tmp[i]); - } - for (int i = 8; i < 10; i++) { - EXPECT_EQ(0, tmp[i]); - } -} - -TEST(CombinedBuffer, CopyUsingStlAlgorithmsAfterShift) { - short buffer1[] = { 1, 2, 3, 4, 5 }; - short buffer2[] = { 6, 7, 8 }; - short tmp[10]; - CombinedBuffer buffer(buffer1, 5, buffer2, 3); - buffer.Shift(6); - fill(tmp, tmp + 10, 0); - for (int i = 0; i < 10; i++) { - EXPECT_EQ(0, tmp[i]); - } - copy(buffer.Begin(), buffer.End(), tmp); - for (int i = 0; i < 2; i++) { - EXPECT_EQ(7 + i, tmp[i]); - } - for (int i = 2; i < 10; i++) { - EXPECT_EQ(0, tmp[i]); - } -} - diff --git a/3rdparty/chromaprint/tests/test_filter.cpp b/3rdparty/chromaprint/tests/test_filter.cpp deleted file mode 100644 index e99a42fc5..000000000 --- a/3rdparty/chromaprint/tests/test_filter.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include -#include -#include -#include "image.h" -#include "filter.h" - -using namespace std; -using namespace Chromaprint; - -TEST(Filter, Filter0) -{ - Image image(2, 2); - image[0][0] = 0.0; - image[0][1] = 1.0; - image[1][0] = 2.0; - image[1][1] = 3.0; - - Filter flt1(0, 0, 1, 1); - IntegralImage integral_image(&image); - ASSERT_FLOAT_EQ(0.0, flt1.Apply(&integral_image, 0)); - ASSERT_FLOAT_EQ(1.0986123, flt1.Apply(&integral_image, 1)); -} - diff --git a/3rdparty/chromaprint/tests/test_filter_utils.cpp b/3rdparty/chromaprint/tests/test_filter_utils.cpp deleted file mode 100644 index e1192918f..000000000 --- a/3rdparty/chromaprint/tests/test_filter_utils.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include "filter_utils.h" - -using namespace std; -using namespace Chromaprint; - -TEST(FilterUtils, CompareSubtract) { - double res = Subtract(2.0, 1.0); - EXPECT_FLOAT_EQ(1.0, res); -} - -TEST(FilterUtils, CompareSubtractLog) { - double res = SubtractLog(2.0, 1.0); - EXPECT_FLOAT_EQ(0.4054651, res); -} - -TEST(FilterUtils, Filter0) { - double data[] = { - 1.0, 2.0, 3.0, - 4.0, 5.0, 6.0, - 7.0, 8.0, 9.0, - }; - Image image(3, data, data + 9); - IntegralImage integral_image(&image); - double res; - res = Filter0(&integral_image, 0, 0, 1, 1, Subtract); - EXPECT_FLOAT_EQ(1.0, res); - res = Filter0(&integral_image, 0, 0, 2, 2, Subtract); - EXPECT_FLOAT_EQ(12.0, res); - res = Filter0(&integral_image, 0, 0, 3, 3, Subtract); - EXPECT_FLOAT_EQ(45.0, res); - res = Filter0(&integral_image, 1, 1, 2, 2, Subtract); - EXPECT_FLOAT_EQ(28.0, res); - res = Filter0(&integral_image, 2, 2, 1, 1, Subtract); - EXPECT_FLOAT_EQ(9.0, res); - res = Filter0(&integral_image, 0, 0, 3, 1, Subtract); - EXPECT_FLOAT_EQ(12.0, res); - res = Filter0(&integral_image, 0, 0, 1, 3, Subtract); - EXPECT_FLOAT_EQ(6.0, res); -} - -TEST(FilterUtils, Filter1) { - double data[] = { - 1.0, 2.0, 3.0, - 3.0, 4.0, 5.0, - 6.0, 7.0, 8.0, - }; - Image image(3, data, data + 9); - IntegralImage integral_image(&image); - double res; - res = Filter1(&integral_image, 0, 0, 1, 1, Subtract); - EXPECT_FLOAT_EQ(1.0, res); // 2 - 1 - res = Filter1(&integral_image, 0, 0, 2, 2, Subtract); - EXPECT_FLOAT_EQ(2.0, res); // 2+4 - 1+3 - res = Filter1(&integral_image, 0, 0, 3, 2, Subtract); - EXPECT_FLOAT_EQ(3.0, res); // 2+4+7 - 1+3+6 -} - -TEST(FilterUtils, Filter2) { - double data[] = { - 1.0, 2.0, 3.0, - 3.0, 4.0, 5.0, - 6.0, 7.0, 8.0, - }; - Image image(3, data, data + 9); - IntegralImage integral_image(&image); - double res; - res = Filter2(&integral_image, 0, 0, 2, 1, Subtract); - EXPECT_FLOAT_EQ(2.0, res); // 3 - 1 - res = Filter2(&integral_image, 0, 0, 2, 2, Subtract); - EXPECT_FLOAT_EQ(4.0, res); // 3+4 - 1+2 - res = Filter2(&integral_image, 0, 0, 2, 3, Subtract); - EXPECT_FLOAT_EQ(6.0, res); // 3+4+5 - 1+2+3 -} - -TEST(FilterUtils, Filter3) { - double data[] = { - 1.0, 2.1, 3.4, - 3.1, 4.1, 5.1, - 6.0, 7.1, 8.0, - }; - Image image(3, data, data + 9); - IntegralImage integral_image(&image); - double res; - res = Filter3(&integral_image, 0, 0, 2, 2, Subtract); - EXPECT_FLOAT_EQ(0.1, res); // 2.1+3.1 - 1+4.1 - res = Filter3(&integral_image, 1, 1, 2, 2, Subtract); - EXPECT_FLOAT_EQ(0.1, res); // 4+8 - 5+7 - res = Filter3(&integral_image, 0, 1, 2, 2, Subtract); - EXPECT_FLOAT_EQ(0.3, res); // 2.1+5.1 - 3.4+4.1 -} - -TEST(FilterUtils, Filter4) { - double data[] = { - 1.0, 2.0, 3.0, - 3.0, 4.0, 5.0, - 6.0, 7.0, 8.0, - }; - Image image(3, data, data + 9); - IntegralImage integral_image(&image); - double res; - res = Filter4(&integral_image, 0, 0, 3, 3, Subtract); - EXPECT_FLOAT_EQ(-13.0, res); // 2+4+7 - (1+3+6) - (3+5+8) -} - -TEST(FilterUtils, Filter5) { - double data[] = { - 1.0, 2.0, 3.0, - 3.0, 4.0, 5.0, - 6.0, 7.0, 8.0, - }; - Image image(3, data, data + 9); - IntegralImage integral_image(&image); - double res; - res = Filter5(&integral_image, 0, 0, 3, 3, Subtract); - EXPECT_FLOAT_EQ(-15.0, res); // 3+4+5 - (1+2+3) - (6+7+8) -} - diff --git a/3rdparty/chromaprint/tests/test_fingerprint_calculator.cpp b/3rdparty/chromaprint/tests/test_fingerprint_calculator.cpp deleted file mode 100644 index dbce20000..000000000 --- a/3rdparty/chromaprint/tests/test_fingerprint_calculator.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include -#include -#include -#include "image.h" -#include "classifier.h" -#include "fingerprint_calculator.h" -#include "utils.h" - -using namespace std; -using namespace Chromaprint; - -TEST(FingerprintCalculator, CalculateSubfingerprint) -{ - Image image(2, 2); - image[0][0] = 0.0; - image[0][1] = 1.0; - image[1][0] = 2.0; - image[1][1] = 3.0; - - Classifier classifiers[] = { - Classifier(Filter(0, 0, 1, 1), Quantizer(0.01, 1.01, 1.5)), - }; - FingerprintCalculator calculator(classifiers, 1); - - IntegralImage integral_image(&image); - EXPECT_EQ(GrayCode(0), calculator.CalculateSubfingerprint(&integral_image, 0)); - EXPECT_EQ(GrayCode(2), calculator.CalculateSubfingerprint(&integral_image, 1)); -} - -TEST(FingerprintCalculator, Calculate) -{ - Image image(2, 3); - image[0][0] = 0.0; - image[0][1] = 1.0; - image[1][0] = 2.0; - image[1][1] = 3.0; - image[2][0] = 4.0; - image[2][1] = 5.0; - - Classifier classifiers[] = { - Classifier(Filter(0, 0, 1, 1), Quantizer(0.01, 1.01, 1.5)), - }; - FingerprintCalculator calculator(classifiers, 1); - - vector fp = calculator.Calculate(&image); - ASSERT_EQ(3, fp.size()); - EXPECT_EQ(GrayCode(0), fp[0]); - EXPECT_EQ(GrayCode(2), fp[1]); - EXPECT_EQ(GrayCode(3), fp[2]); -} - diff --git a/3rdparty/chromaprint/tests/test_fingerprint_compressor.cpp b/3rdparty/chromaprint/tests/test_fingerprint_compressor.cpp deleted file mode 100644 index c130ebfbe..000000000 --- a/3rdparty/chromaprint/tests/test_fingerprint_compressor.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include -#include -#include -#include -#include -#include "image.h" -#include "classifier.h" -#include "fingerprint_compressor.h" -#include "utils.h" -#include "test_utils.h" - -using namespace std; -using namespace Chromaprint; - -TEST(FingerprintCompressor, OneItemOneBit) -{ - FingerprintCompressor compressor; - - int32_t fingerprint[] = { 1 }; - string value = compressor.Compress(vector(fingerprint, fingerprint + 1)); - - char expected[] = { 0, 0, 0, 1, 1 }; - CheckString(value, expected, sizeof(expected)/sizeof(expected[0])); -} - -TEST(FingerprintCompressor, OneItemThreeBits) -{ - FingerprintCompressor compressor; - - int32_t fingerprint[] = { 7 }; - string value = compressor.Compress(vector(fingerprint, fingerprint + 1)); - - char expected[] = { 0, 0, 0, 1, 73, 0 }; - CheckString(value, expected, sizeof(expected)/sizeof(expected[0])); -} - -TEST(FingerprintCompressor, OneItemOneBitExcept) -{ - FingerprintCompressor compressor; - - int32_t fingerprint[] = { 1<<6 }; - string value = compressor.Compress(vector(fingerprint, fingerprint + 1)); - - char expected[] = { 0, 0, 0, 1, 7, 0 }; - CheckString(value, expected, sizeof(expected)/sizeof(expected[0])); -} - -TEST(FingerprintCompressor, OneItemOneBitExcept2) -{ - FingerprintCompressor compressor; - - int32_t fingerprint[] = { 1<<8 }; - string value = compressor.Compress(vector(fingerprint, fingerprint + 1)); - - char expected[] = { 0, 0, 0, 1, 7, 2 }; - CheckString(value, expected, sizeof(expected)/sizeof(expected[0])); -} - -TEST(FingerprintCompressor, TwoItems) -{ - FingerprintCompressor compressor; - - int32_t fingerprint[] = { 1, 0 }; - string value = compressor.Compress(vector(fingerprint, fingerprint + 2)); - - char expected[] = { 0, 0, 0, 2, 65, 0 }; - CheckString(value, expected, sizeof(expected)/sizeof(expected[0])); -} - -TEST(FingerprintCompressor, TwoItemsNoChange) -{ - FingerprintCompressor compressor; - - int32_t fingerprint[] = { 1, 1 }; - string value = compressor.Compress(vector(fingerprint, fingerprint + 2)); - - char expected[] = { 0, 0, 0, 2, 1, 0 }; - CheckString(value, expected, sizeof(expected)/sizeof(expected[0])); -} diff --git a/3rdparty/chromaprint/tests/test_fingerprint_decompressor.cpp b/3rdparty/chromaprint/tests/test_fingerprint_decompressor.cpp deleted file mode 100644 index 98d77d6b1..000000000 --- a/3rdparty/chromaprint/tests/test_fingerprint_decompressor.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include -#include "fingerprint_decompressor.h" -#include "utils.h" -#include "test_utils.h" - -using namespace std; -using namespace Chromaprint; - -TEST(FingerprintDecompressor, OneItemOneBit) -{ - int32_t expected[] = { 1 }; - char data[] = { 0, 0, 0, 1, 1 }; - - int algorithm = 1; - vector value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm); - CheckFingerprints(value, expected, NELEMS(expected)); - ASSERT_EQ(0, algorithm); -} - - -TEST(FingerprintDecompressor, OneItemThreeBits) -{ - int32_t expected[] = { 7 }; - char data[] = { 0, 0, 0, 1, 73, 0 }; - - int algorithm = 1; - vector value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm); - CheckFingerprints(value, expected, NELEMS(expected)); - ASSERT_EQ(0, algorithm); -} - -TEST(FingerprintDecompressor, OneItemOneBitExcept) -{ - int32_t expected[] = { 1<<6 }; - char data[] = { 0, 0, 0, 1, 7, 0 }; - - int algorithm = 1; - vector value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm); - CheckFingerprints(value, expected, NELEMS(expected)); - ASSERT_EQ(0, algorithm); -} - -TEST(FingerprintDecompressor, OneItemOneBitExcept2) -{ - int32_t expected[] = { 1<<8 }; - char data[] = { 0, 0, 0, 1, 7, 2 }; - - int algorithm = 1; - vector value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm); - CheckFingerprints(value, expected, NELEMS(expected)); - ASSERT_EQ(0, algorithm); -} - -TEST(FingerprintDecompressor, TwoItems) -{ - int32_t expected[] = { 1, 0 }; - char data[] = { 0, 0, 0, 2, 65, 0 }; - - int algorithm = 1; - vector value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm); - CheckFingerprints(value, expected, NELEMS(expected)); - ASSERT_EQ(0, algorithm); -} - -TEST(FingerprintDecompressor, TwoItemsNoChange) -{ - int32_t expected[] = { 1, 1 }; - char data[] = { 0, 0, 0, 2, 1, 0 }; - - int algorithm = 1; - vector value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm); - CheckFingerprints(value, expected, NELEMS(expected)); - ASSERT_EQ(0, algorithm); -} - diff --git a/3rdparty/chromaprint/tests/test_integral_image.cpp b/3rdparty/chromaprint/tests/test_integral_image.cpp deleted file mode 100644 index bb9a97985..000000000 --- a/3rdparty/chromaprint/tests/test_integral_image.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include "integral_image.h" - -using namespace std; -using namespace Chromaprint; - -TEST(IntegralImage, Basic2D) { - double data[] = { - 1.0, 2.0, - 3.0, 4.0, - }; - Image image(2, data, data + 4); - IntegralImage integral_image(&image); - EXPECT_FLOAT_EQ(1.0, integral_image[0][0]); - EXPECT_FLOAT_EQ(3.0, integral_image[0][1]); - EXPECT_FLOAT_EQ(4.0, integral_image[1][0]); - EXPECT_FLOAT_EQ(10.0, integral_image[1][1]); -} - -TEST(IntegralImage, Vertical1D) { - double data[] = { - 1.0, 2.0, 3.0 - }; - Image image(1, data, data + 3); - IntegralImage integral_image(&image); - EXPECT_FLOAT_EQ(1.0, integral_image[0][0]); - EXPECT_FLOAT_EQ(3.0, integral_image[1][0]); - EXPECT_FLOAT_EQ(6.0, integral_image[2][0]); -} - -TEST(IntegralImage, Horizontal1D) { - double data[] = { - 1.0, 2.0, 3.0 - }; - Image image(3, data, data + 3); - IntegralImage integral_image(&image); - EXPECT_FLOAT_EQ(1.0, integral_image[0][0]); - EXPECT_FLOAT_EQ(3.0, integral_image[0][1]); - EXPECT_FLOAT_EQ(6.0, integral_image[0][2]); -} diff --git a/3rdparty/chromaprint/tests/test_lloyds.cpp b/3rdparty/chromaprint/tests/test_lloyds.cpp deleted file mode 100644 index 9fe2297f8..000000000 --- a/3rdparty/chromaprint/tests/test_lloyds.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include -#include -#include "lloyds.h" - -using namespace std; - -template -ostream &operator<<(ostream &stream, const vector &vec) -{ - for (int i = 0; i < vec.size(); i++) { - if (i != 0) - stream << ", "; - stream << vec[i]; - } - return stream; -} - -/*TEST(Lloyds, Long) { - double signal[] = { - -2.23622, -2.2133, -2.08922, -2.02973, -2.01912, -2.00194, -1.94793, -1.92903, -1.90671, -1.90311, -1.86394, -1.82542, -1.82281, -1.77955, -1.77286, -1.77119, -1.76317, -1.74447, -1.74447, -1.71927, -1.71244, -1.70758, -1.69632, -1.69448, -1.68845, -1.68842, -1.65839, -1.64934, -1.63575, -1.61216, -1.56943, -1.56546, -1.5601, -1.5584, -1.53875, -1.52408, -1.51576, -1.47345, -1.44838, -1.44712, -1.43751, -1.43722, -1.43159, -1.41818, -1.41585, -1.36654, -1.36556, -1.36486, -1.3596, -1.35941, -1.35301, -1.35301, -1.35145, -1.34479, -1.34443, -1.3441, -1.3381, -1.3334, -1.31715, -1.31105, -1.31071, -1.30166, -1.29944, -1.29715, -1.29669, -1.29634, -1.28696, -1.28504, -1.27143, -1.26548, -1.26533, -1.26421, -1.26054, -1.25978, -1.25631, -1.24751, -1.23887, -1.23797, -1.23588, -1.22391, -1.21961, -1.21559, -1.21499, -1.19502, -1.19009, -1.18784, -1.18746, -1.18264, -1.17917, -1.17597, -1.17482, -1.1664, -1.15644, -1.15584, -1.15317, -1.14694, -1.14341, -1.14246, -1.14234, -1.14027, -1.13955, -1.13745, -1.13674, -1.12764, -1.12735, -1.12729, -1.12645, -1.12578, -1.12533, -1.12131, -1.11019, -1.10879, -1.10357, -1.09973, -1.09187, -1.09187, -1.06664, -1.06356, -1.0554, -1.0492, -1.04506, -1.04027, -1.03942, -1.03896, -1.034, -1.03285, -1.02334, -1.02084, -1.01993, -1.01447, -1.01447, -1.01447, -1.00864, -1.00689, -1.00471, -1.00125, -0.999809, -0.998627, -0.998156, -0.994751, -0.994212, -0.993412, -0.992572, -0.992572, -0.992548, -0.992472, -0.989607, -0.987201, -0.982932, -0.982652, -0.980823, -0.976318, -0.974594, -0.973334, -0.97326, -0.971969, -0.970954, -0.964969, -0.963816, -0.960578, -0.959536, -0.95708, -0.953791, -0.953782, -0.952128, -0.951757, -0.95172, -0.951264, -0.950896, -0.949007, -0.947225, -0.945958, -0.945852, -0.945044, -0.94482, -0.940381, -0.940254, -0.940084, -0.939844, -0.937978, -0.935127, -0.93345, -0.931299, -0.931147, -0.929513, -0.927091, -0.926682, -0.926458, -0.925325, -0.918487, -0.917891, -0.917015, -0.916352, -0.915526, -0.915489, -0.913747, -0.91204, -0.911457, -0.911281, -0.910753, -0.909806, -0.909361, -0.908686, -0.907, -0.906509, -0.903637, -0.902177, -0.896958, -0.896304, -0.895733, -0.889965, -0.886484, -0.884943, -0.882143, -0.879831, -0.879507, -0.876134, -0.875782, -0.873226, -0.873167, -0.872282, -0.870152, -0.869655, -0.869655, -0.866992, -0.862656, -0.862331, -0.861969, -0.861246, -0.856819, -0.854323, -0.853294, -0.846832, -0.843682, -0.842113, -0.840478, -0.835353, -0.83055, -0.828979, -0.828979, -0.828088, -0.826904, -0.826844, -0.826474, -0.820101, -0.819027, -0.819027, -0.818121, -0.812784, -0.812206, -0.810112, -0.806803, -0.805296, -0.80126, -0.800501, -0.798129, -0.797067, -0.786663, -0.785991, -0.784662, -0.78212, -0.776524, -0.774306, -0.772335, -0.771675, -0.771675, -0.77125, -0.770083, -0.769165, -0.767499, -0.766419, -0.763909, -0.762582, -0.76243, -0.761753, -0.761182, -0.759494, -0.755514, -0.745122, -0.742554, -0.739007, -0.73575, -0.735359, -0.73376, -0.732161, -0.728712, -0.726951, -0.726218, -0.725935, -0.724686, -0.722143, -0.722044, -0.721563, -0.721248, -0.720543, -0.719718, -0.716511, -0.714431, -0.714329, -0.712779, -0.712512, -0.712512, -0.711802, -0.71157, -0.709608, -0.706909, -0.706774, -0.704839, -0.703444, -0.702687, -0.70263, -0.702272, -0.700726, -0.700691, -0.700566, -0.698961, -0.697583, -0.697153, -0.696813, -0.696062, -0.695309, -0.694557, -0.691675, -0.691434, -0.687548, -0.686447, -0.684052, -0.68283, -0.682705, -0.682523, -0.682514, -0.679172, -0.675747, -0.675161, -0.673046, -0.670132, -0.663973, -0.659537, -0.655187, -0.65481, -0.653818, -0.65335, -0.653181, -0.649845, -0.649723, -0.648533, -0.647648, -0.645932, -0.645885, -0.645736, -0.643418, -0.642324, -0.642275, -0.641053, -0.641053, -0.636907, -0.635015, -0.634658, -0.632863, -0.629322, -0.629234, -0.628869, -0.627114, -0.626578, -0.626576, -0.62511, -0.625091, -0.621436, -0.620774, -0.616916, -0.616051, -0.612722, -0.611527, -0.610163, -0.609325, -0.606185, -0.606169, -0.606019, -0.603731, -0.602434, -0.596665, -0.596236, -0.595822, -0.594053, -0.588736, -0.588164, -0.586796, -0.586709, -0.585038, -0.583978, -0.583929, -0.582533, -0.576205, -0.57511 - }; - vector r = lloyds(signal, signal + sizeof(signal) / sizeof(signal[0]), 10); - EXPECT_EQ(9, r.size()); - EXPECT_FLOAT_EQ(-2.15126, r[0]); - EXPECT_FLOAT_EQ(-1.95019, r[1]); - EXPECT_FLOAT_EQ(-1.72034, r[2]); - EXPECT_FLOAT_EQ(-1.42570, r[3]); - EXPECT_FLOAT_EQ(-1.23976, r[4]); - EXPECT_FLOAT_EQ(-1.06092, r[5]); - EXPECT_FLOAT_EQ(-0.93395, r[6]); - EXPECT_FLOAT_EQ(-0.81530, r[7]); - EXPECT_FLOAT_EQ(-0.68837, r[8]); -}*/ - -TEST(LLoyds, Lloyds1) { - double data[] = { - 1.0, 1.1, 1.2, - 3.0, 3.1, 3.2, - }; - vector sig(data, data + 6); - vector table = lloyds(sig, 2); - EXPECT_EQ(1, table.size()); - EXPECT_FLOAT_EQ(2.1, table[0]); -} - -TEST(LLoyds, Lloyds2) { - double data[] = { - 1.0, 1.1, 1.2, - }; - vector sig(data, data + 3); - vector table = lloyds(sig, 2); - EXPECT_EQ(1, table.size()); - EXPECT_FLOAT_EQ(1.075, table[0]); -} - -TEST(LLoyds, Lloyds3) { - double data[] = { - 1.0, 1.1, 1.2, - }; - vector sig(data, data + 3); - vector table = lloyds(sig, 3); - EXPECT_EQ(2, table.size()); - EXPECT_FLOAT_EQ(1.05, table[0]); - EXPECT_FLOAT_EQ(1.15, table[1]); -} - -TEST(LLoyds, Lloyds4) { - double data[] = { - 435,219,891,906,184,572,301,892,875,121,245,146,640,137,938,25,668,288,848,790,141,890,528,145,289,861,339,769,293,757 - }; - vector sig(data, data + 30); - vector table = lloyds(sig, 4); - EXPECT_EQ(3, table.size()); - EXPECT_FLOAT_EQ(214.77678, table[0]); - EXPECT_FLOAT_EQ(451.5625, table[1]); - EXPECT_FLOAT_EQ(729.04547, table[2]); -} - - diff --git a/3rdparty/chromaprint/tests/test_quantizer.cpp b/3rdparty/chromaprint/tests/test_quantizer.cpp deleted file mode 100644 index 68f176922..000000000 --- a/3rdparty/chromaprint/tests/test_quantizer.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include "quantizer.h" - -using namespace std; -using namespace Chromaprint; - -TEST(Quantizer, Quantize) { - Quantizer q(0.0, 0.1, 0.3); - EXPECT_EQ(0, q.Quantize(-0.1)); - EXPECT_EQ(1, q.Quantize(0.0)); - EXPECT_EQ(1, q.Quantize(0.03)); - EXPECT_EQ(2, q.Quantize(0.1)); - EXPECT_EQ(2, q.Quantize(0.13)); - EXPECT_EQ(3, q.Quantize(0.3)); - EXPECT_EQ(3, q.Quantize(0.33)); - EXPECT_EQ(3, q.Quantize(1000.0)); -} diff --git a/3rdparty/chromaprint/tests/test_silence_remover.cpp b/3rdparty/chromaprint/tests/test_silence_remover.cpp deleted file mode 100644 index 7f067f7fa..000000000 --- a/3rdparty/chromaprint/tests/test_silence_remover.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include -#include -#include "test_utils.h" -#include "silence_remover.h" -#include "audio_buffer.h" -#include "utils.h" - -using namespace std; -using namespace Chromaprint; - -TEST(SilenceRemover, PassThrough) -{ - short samples[] = { 1, 2, 3, 4, 5, 6 }; - vector data(samples, samples + 6); - - boost::scoped_ptr buffer(new AudioBuffer()); - boost::scoped_ptr processor(new SilenceRemover(buffer.get())); - processor->Reset(44100, 1); - processor->Consume(&data[0], data.size()); - processor->Flush(); - - ASSERT_EQ(data.size(), buffer->data().size()); - for (size_t i = 0; i < data.size(); i++) { - ASSERT_EQ(data[i], buffer->data()[i]) << "Signals differ at index " << i; - } -} - -TEST(SilenceRemover, RemoveLeadingSilence) -{ - short samples1[] = { 0, 0, 1, 2, 0, 4, 5, 0 }; - vector data1(samples1, samples1 + 8); - - short samples2[] = { 1, 2, 0, 4, 5, 0 }; - vector data2(samples2, samples2 + 6); - - boost::scoped_ptr buffer(new AudioBuffer()); - boost::scoped_ptr processor(new SilenceRemover(buffer.get())); - processor->Reset(44100, 1); - processor->Consume(&data1[0], data1.size()); - processor->Flush(); - - ASSERT_EQ(data2.size(), buffer->data().size()); - for (size_t i = 0; i < data2.size(); i++) { - ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i; - } -} diff --git a/3rdparty/chromaprint/tests/test_utils.cpp b/3rdparty/chromaprint/tests/test_utils.cpp deleted file mode 100644 index c26e50973..000000000 --- a/3rdparty/chromaprint/tests/test_utils.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include -#include -#include -#include "utils.h" - -using namespace std; -using namespace Chromaprint; - -TEST(Utils, PrepareHammingWindow) { - double window_ex[10] = { 0.08, 0.187619556165, 0.460121838273, 0.77, 0.972258605562, 0.972258605562, 0.77, 0.460121838273, 0.187619556165, 0.08}; - double window[10]; - PrepareHammingWindow(window, window + 10); - for (int i = 0; i < 10; i++) { - EXPECT_FLOAT_EQ(window_ex[i], window[i]); - } -} - -TEST(Utils, ApplyWindow1) { - double window_ex[10] = { 0.08, 0.187619556165, 0.460121838273, 0.77, 0.972258605562, 0.972258605562, 0.77, 0.460121838273, 0.187619556165, 0.08}; - double window[10]; - short input[10]; - double output[10]; - PrepareHammingWindow(window, window + 10); - fill(input, input + 10, numeric_limits::max()); - double scale = 1.0 / numeric_limits::max(); - ApplyWindow(input, window, output, 10, scale); - for (int i = 0; i < 10; i++) { - EXPECT_FLOAT_EQ(window_ex[i], output[i]); - } -} - -TEST(Utils, ApplyWindow2) { - double window[10]; - short input[10]; - double output[10]; - PrepareHammingWindow(window, window + 10); - fill(input, input + 10, 0); - double scale = 1.0 / numeric_limits::max(); - ApplyWindow(input, window, output, 10, scale); - for (int i = 0; i < 10; i++) { - EXPECT_FLOAT_EQ(0.0, output[i]); - } -} - -TEST(Utils, Sum) { - double data[] = { 0.1, 0.2, 0.4, 1.0 }; - EXPECT_FLOAT_EQ(1.7, Sum(data, data + 4)); -} - -TEST(Utils, EuclideanNorm) { - double data[] = { 0.1, 0.2, 0.4, 1.0 }; - EXPECT_FLOAT_EQ(1.1, EuclideanNorm(data, data + 4)); -} - -TEST(Utils, NormalizeVector) { - double data[] = { 0.1, 0.2, 0.4, 1.0 }; - double normalized_data[] = { 0.090909, 0.181818, 0.363636, 0.909091 }; - NormalizeVector(data, data + 4, EuclideanNorm, 0.01); - for (int i = 0; i < 4; i++) { - EXPECT_NEAR(normalized_data[i], data[i], 1e-5) << "Wrong data at index " << i; - } -} - -TEST(Utils, NormalizeVectorNearZero) { - double data[] = { 0.0, 0.001, 0.002, 0.003 }; - NormalizeVector(data, data + 4, EuclideanNorm, 0.01); - for (int i = 0; i < 4; i++) { - EXPECT_FLOAT_EQ(0.0, data[i]) << "Wrong data at index " << i; - } -} - -TEST(Utils, NormalizeVectorZero) { - double data[] = { 0.0, 0.0, 0.0, 0.0 }; - NormalizeVector(data, data + 4, EuclideanNorm, 0.01); - for (int i = 0; i < 4; i++) { - EXPECT_FLOAT_EQ(0.0, data[i]) << "Wrong data at index " << i; - } -} - -TEST(Utils, UnsignedToSigned) { - EXPECT_EQ(numeric_limits::max(), UnsignedToSigned(0x7FFFFFFFU)); - EXPECT_EQ(-1, UnsignedToSigned(0xFFFFFFFFU)); - EXPECT_EQ(-2, UnsignedToSigned(0xFFFFFFFEU)); - EXPECT_EQ(numeric_limits::min(), UnsignedToSigned(0x80000000U)); - EXPECT_EQ(numeric_limits::min() + 1, UnsignedToSigned(0x80000001U)); -} - -TEST(Utils, IsNaN) { - EXPECT_FALSE(IsNaN(0.0)); - EXPECT_TRUE(IsNaN(sqrt(-1.0))); -} diff --git a/3rdparty/chromaprint/tests/test_utils.h b/3rdparty/chromaprint/tests/test_utils.h deleted file mode 100644 index c5898db86..000000000 --- a/3rdparty/chromaprint/tests/test_utils.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef CHROMAPRINT_TESTS_UTILS_H_ -#define CHROMAPRINT_TESTS_UTILS_H_ - -#include -#include -#include -#ifdef HAVE_CONFIG_H -#include -#endif - -#define NELEMS(x) (sizeof(x)/sizeof(x[0])) - -inline void CheckString(std::string actual, char *expected, int expected_size) -{ - ASSERT_EQ(expected_size, actual.size()); - for (int i = 0; i < expected_size; i++) { - EXPECT_EQ(expected[i], actual[i]) << "Different at index " << i; - } -} - -inline void CheckFingerprints(std::vector actual, int32_t *expected, int expected_size) -{ - ASSERT_EQ(expected_size, actual.size()); - for (int i = 0; i < expected_size; i++) { - EXPECT_EQ(expected[i], actual[i]) << "Different at index " << i; - } -} - -inline std::vector LoadAudioFile(const std::string &file_name) -{ - std::string path = TESTS_DIR + file_name; - std::ifstream file(path.c_str(), std::ifstream::in); - file.seekg(0, std::ios::end); - int length = file.tellg(); - file.seekg(0, std::ios::beg); - std::vector data(length / 2); - file.read((char *)&data[0], length); - file.close(); - return data; -} - -#endif diff --git a/3rdparty/chromaprint/tools/CMakeLists.txt b/3rdparty/chromaprint/tools/CMakeLists.txt deleted file mode 100644 index 7c3de7994..000000000 --- a/3rdparty/chromaprint/tools/CMakeLists.txt +++ /dev/null @@ -1,63 +0,0 @@ -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/../src - ${FFMPEG_LIBAVCODEC_INCLUDE_DIRS} - ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS} - ${FFMPEG_LIBAVUTIL_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} - ${TAGLIB_INCLUDES} -) - -if(BUILD_EXTRA_TOOLS) - - add_executable(resample resample.cpp) - target_link_libraries(resample chromaprint_p - ${FFMPEG_LIBAVFORMAT_LIBRARIES} - ${FFMPEG_LIBAVCODEC_LIBRARIES} - ${FFMPEG_LIBAVUTIL_LIBRARIES}) - - add_executable(decode decode.cpp) - target_link_libraries(decode chromaprint_p - ${FFMPEG_LIBAVFORMAT_LIBRARIES} - ${FFMPEG_LIBAVCODEC_LIBRARIES} - ${FFMPEG_LIBAVUTIL_LIBRARIES}) - - add_executable(chromagram chromagram.cpp) - target_link_libraries(chromagram chromaprint_p - ${FFMPEG_LIBAVFORMAT_LIBRARIES} - ${FFMPEG_LIBAVCODEC_LIBRARIES} - ${FFMPEG_LIBAVUTIL_LIBRARIES} - -lpng) - - add_executable(spectrogram spectrogram.cpp) - target_link_libraries(spectrogram chromaprint_p - ${FFMPEG_LIBAVFORMAT_LIBRARIES} - ${FFMPEG_LIBAVCODEC_LIBRARIES} - ${FFMPEG_LIBAVUTIL_LIBRARIES} - -lpng) - - add_executable(learn_filters learn_filters.cpp) - target_link_libraries(learn_filters chromaprint_p - ${FFMPEG_LIBAVFORMAT_LIBRARIES} - ${FFMPEG_LIBAVCODEC_LIBRARIES} - ${FFMPEG_LIBAVUTIL_LIBRARIES} - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY}) - - add_executable(fpeval fpeval.cpp) - target_link_libraries(fpeval chromaprint_p - ${FFMPEG_LIBAVFORMAT_LIBRARIES} - ${FFMPEG_LIBAVCODEC_LIBRARIES} - ${FFMPEG_LIBAVUTIL_LIBRARIES} - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY}) - -endif(BUILD_EXTRA_TOOLS) - -if(NOT MSVC) -add_executable(fpcollect fpcollect.cpp) -target_link_libraries(fpcollect chromaprint_p - ${FFMPEG_LIBAVFORMAT_LIBRARIES} - ${FFMPEG_LIBAVCODEC_LIBRARIES} - ${FFMPEG_LIBAVUTIL_LIBRARIES} - ${TAGLIB_LIBRARIES}) -endif() diff --git a/3rdparty/chromaprint/tools/chromagram.cpp b/3rdparty/chromaprint/tools/chromagram.cpp deleted file mode 100644 index 17333ff08..000000000 --- a/3rdparty/chromaprint/tools/chromagram.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include - -using namespace std; - -#include "ext/ffmpeg_decoder.h" -#include "ext/audio_dumper.h" -#include "audio_processor.h" -#include "chroma.h" -#include "spectral_centroid.h" -#include "chroma_normalizer.h" -#include "chroma_resampler.h" -#include "chroma_filter.h" -#include "fft.h" -#include "audio_processor.h" -#include "image.h" -#include "image_builder.h" -#include "utils.h" -#include "ext/image_utils.h" - -static const int SAMPLE_RATE = 11025; -static const int FRAME_SIZE = 4096; -static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720; -static const int MIN_FREQ = 28; -static const int MAX_FREQ = 3520; -static const int MAX_FILTER_WIDTH = 20; - -static const int kChromaFilterSize = 5; -static const double kChromaFilterCoefficients[] = { 0.25, 0.75, 1.0, 0.75, 0.25 }; - -int main(int argc, char **argv) -{ - if (argc < 3) { - cerr << "Usage: " << argv[0] << " AUDIOFILE IMAGEFILE\n"; - return 1; - } - - string file_name(argv[1]); - cout << "Loading file " << file_name << "\n"; - - Decoder decoder(file_name); - if (!decoder.Open()) { - cerr << "ERROR: " << decoder.LastError() << "\n"; - return 2; - } - - Chromaprint::Image image(12); - Chromaprint::ImageBuilder image_builder(&image); - Chromaprint::ChromaNormalizer chroma_normalizer(&image_builder); - Chromaprint::ChromaFilter chroma_filter(kChromaFilterCoefficients, kChromaFilterSize, &chroma_normalizer); - //Chromaprint::Chroma chroma(MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &chroma_normalizer); - Chromaprint::Chroma chroma(MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &chroma_filter); - Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, &chroma); - Chromaprint::AudioProcessor processor(SAMPLE_RATE, &fft); - - processor.Reset(decoder.SampleRate(), decoder.Channels()); - decoder.Decode(&processor); - processor.Flush(); - - //Chromaprint::ExportTextImage(&image, argv[2]); - Chromaprint::ExportImage(&image, argv[2]); - - return 0; -} - diff --git a/3rdparty/chromaprint/tools/decode.cpp b/3rdparty/chromaprint/tools/decode.cpp deleted file mode 100644 index a86800469..000000000 --- a/3rdparty/chromaprint/tools/decode.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include - -using namespace std; - -#include "ext/ffmpeg_decoder.h" -#include "ext/audio_dumper.h" - -int main(int argc, char **argv) -{ - if (argc < 3) { - cerr << "Usage: " << argv[0] << " FILENAME\n"; - return 1; - } - - string file_name(argv[1]); - Decoder decoder(file_name); - if (!decoder.Open()) { - cerr << "ERROR: " << decoder.LastError() << "\n"; - return 2; - } - - AudioDumper dumper(argv[2]); - decoder.Decode(&dumper); - - return 0; -} - diff --git a/3rdparty/chromaprint/tools/fillpuid.py b/3rdparty/chromaprint/tools/fillpuid.py deleted file mode 100755 index af37b4a3d..000000000 --- a/3rdparty/chromaprint/tools/fillpuid.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python - -import time -import sys -from optparse import OptionParser -import subprocess -import os.path -from xml.etree import ElementTree - - -usage = "usage: %prog [options] logfile" -parser = OptionParser(usage=usage) -parser.add_option("-a", "--musicdns-apikey", dest="musicdns_api_key", metavar="KEY", - help="MusicDNS API key") -parser.add_option("-g", "--genpuid", dest="genpuid_path", metavar="PATH", - help="path to the GenPUID binary", default="genpuid") - -(options, args) = parser.parse_args() -if len(args) != 1: - parser.error("no log file specified") - - -def read_log_file(input): - group = {} - for line in input: - line = line.strip() - if not line: - if group: - yield group - group = {} - continue - name, value = line.split('=', 1) - group[name] = value - if group: - yield group - - -def make_groups(input, size=10): - group = [] - for entry in input: - group.append(entry) - if len(group) >= size: - yield group - group = [] - if group: - yield group - - - -def write_log_file(entry): - for row in entry.iteritems(): - print '%s=%s' % row - print - - -def call_genpuid(entries): - paths = [e['FILENAME'] for e in entries] - process = subprocess.Popen([options.genpuid_path, options.musicdns_api_key, '-xml'] + paths, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = process.communicate() - tree = ElementTree.fromstring('' + out) - puids = {} - for track in tree.findall("track"): - if 'puid' in track.attrib and 'file' in track.attrib: - puids[os.path.normpath(track.attrib['file']).encode('iso-8859-1')] = track.attrib['puid'] - for entry in entries: - path = os.path.normpath(entry['FILENAME']) - if path in puids: - entry['PUID'] = puids[path] - - -for entries in make_groups(read_log_file(open(args[0]) if args[0] != '-' else sys.stdin), 20): - call_genpuid([e for e in entries if 'MBID' not in e]) - for entry in entries: - print >>sys.stderr, entry['FILENAME'] - write_log_file(entry) - diff --git a/3rdparty/chromaprint/tools/fpcollect.cpp b/3rdparty/chromaprint/tools/fpcollect.cpp deleted file mode 100644 index 8ffdb3ec5..000000000 --- a/3rdparty/chromaprint/tools/fpcollect.cpp +++ /dev/null @@ -1,323 +0,0 @@ -#include -#include -#include -//#include -#include -#include -#include -#include "chromaprint.h" -#include "fingerprinter.h" -#include "fingerprinter_configuration.h" -#include "fingerprint_compressor.h" -#include "base64.h" -#include "ext/ffmpeg_decoder.h" - -using namespace std; - -static const int kChromaprintAlgorithm = CHROMAPRINT_ALGORITHM_DEFAULT; - -typedef vector string_vector; - -void FindFiles(const string &dirname, string_vector *result, time_t changed_since) -{ - DIR *dirp = opendir(dirname.c_str()); - if (!dirp) { - if (errno == ENOTDIR) { - result->push_back(dirname); - } - return; - } - while (dirp) { - struct dirent *dp; - if ((dp = readdir(dirp)) != NULL) { - struct stat sp; - string filename = dirname + '/' + string(dp->d_name); - stat(filename.c_str(), &sp); - if (S_ISREG(sp.st_mode)) { - //cerr << "file " << filename << " mtime=" << sp.st_mtime << " ch=" << changed_since << "\n"; - if (!changed_since || sp.st_mtime >= changed_since) { - result->push_back(filename); - } - } - if (S_ISDIR(sp.st_mode) && dp->d_name[0] != '.') { - FindFiles(filename, result, changed_since); - } - } - else { - break; - } - } - closedir(dirp); -} - -string_vector FindFiles(const string_vector &files, time_t changed_since) -{ - string_vector result; - for (size_t i = 0; i < files.size(); i++) { - FindFiles(files[i], &result, changed_since); - } - sort(result.begin(), result.end()); - return result; -} - -#define DISPATCH_TAGLIB_FILE(type, file) \ - { \ - type *tmp = dynamic_cast(file); \ - if (tmp) { \ - return ExtractMBIDFromFile(tmp); \ - } \ - } - -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef TAGLIB_WITH_ASF -#include -#endif -#ifdef TAGLIB_WITH_MP4 -#include -#endif -#include -#include -#include - -string ExtractMBIDFromXiphComment(TagLib::Ogg::XiphComment *tag) -{ - string key = "MUSICBRAINZ_TRACKID"; - if (tag && tag->fieldListMap().contains(key)) { - return tag->fieldListMap()[key].front().to8Bit(true); - } - return string(); -} - -string ExtractMBIDFromAPETag(TagLib::APE::Tag *tag) -{ - string key = "MUSICBRAINZ_TRACKID"; - if (tag && tag->itemListMap().contains(key)) { - return tag->itemListMap()[key].toString().to8Bit(true); - } - return string(); -} - -string ExtractMBIDFromFile(TagLib::Ogg::Vorbis::File *file) -{ - return ExtractMBIDFromXiphComment(file->tag()); -} - -string ExtractMBIDFromFile(TagLib::Ogg::FLAC::File *file) -{ - return ExtractMBIDFromXiphComment(file->tag()); -} - -string ExtractMBIDFromFile(TagLib::Ogg::Speex::File *file) -{ - return ExtractMBIDFromXiphComment(file->tag()); -} - -string ExtractMBIDFromFile(TagLib::FLAC::File *file) -{ - return ExtractMBIDFromXiphComment(file->xiphComment()); -} - -string ExtractMBIDFromFile(TagLib::MPC::File *file) -{ - return ExtractMBIDFromAPETag(file->APETag()); -} - -string ExtractMBIDFromFile(TagLib::WavPack::File *file) -{ - return ExtractMBIDFromAPETag(file->APETag()); -} - -/*string ExtractMBIDFromFile(TagLib::APE::File *file) -{ - return ExtractMBIDFromAPETag(file->APETag()); -}*/ - -#ifdef TAGLIB_WITH_ASF -string ExtractMBIDFromFile(TagLib::ASF::File *file) -{ - string key = "MusicBrainz/Track Id"; - TagLib::ASF::Tag *tag = file->tag(); - if (tag && tag->attributeListMap().contains(key)) { - return tag->attributeListMap()[key].front().toString().to8Bit(true); - } - return string(); -} -#endif - -#ifdef TAGLIB_WITH_MP4 -string ExtractMBIDFromFile(TagLib::MP4::File *file) -{ - string key = "----:com.apple.iTunes:MusicBrainz Track Id"; - TagLib::MP4::Tag *tag = file->tag(); - if (tag && tag->itemListMap().contains(key)) { - return tag->itemListMap()[key].toStringList().toString().to8Bit(true); - } - return string(); -} -#endif - -string ExtractMBIDFromFile(TagLib::MPEG::File *file) -{ - TagLib::ID3v2::Tag *tag = file->ID3v2Tag(); - if (!tag) { - return string(); - } - TagLib::ID3v2::FrameList ufid = tag->frameListMap()["UFID"]; - if (!ufid.isEmpty()) { - for (TagLib::ID3v2::FrameList::Iterator i = ufid.begin(); i != ufid.end(); i++) { - TagLib::ID3v2::UniqueFileIdentifierFrame *frame = dynamic_cast(*i); - if (frame && frame->owner() == "http://musicbrainz.org") { - TagLib::ByteVector id = frame->identifier(); - return string(id.data(), id.size()); - } - } - } - return string(); -} - -string ExtractMusicBrainzTrackID(TagLib::File *file) -{ - DISPATCH_TAGLIB_FILE(TagLib::FLAC::File, file); - DISPATCH_TAGLIB_FILE(TagLib::Ogg::Vorbis::File, file); - DISPATCH_TAGLIB_FILE(TagLib::Ogg::FLAC::File, file); - DISPATCH_TAGLIB_FILE(TagLib::Ogg::Speex::File, file); - DISPATCH_TAGLIB_FILE(TagLib::MPC::File, file); - DISPATCH_TAGLIB_FILE(TagLib::WavPack::File, file); -#ifdef TAGLIB_WITH_ASF - DISPATCH_TAGLIB_FILE(TagLib::ASF::File, file); -#endif -#ifdef TAGLIB_WITH_MP4 - DISPATCH_TAGLIB_FILE(TagLib::MP4::File, file); -#endif - DISPATCH_TAGLIB_FILE(TagLib::MPEG::File, file); - return string(); -} - -bool ReadTags(const string &filename, bool ignore_missing_mbid) -{ - TagLib::FileRef file(filename.c_str(), true); - if (file.isNull()) - return false; - TagLib::Tag *tags = file.tag(); - TagLib::AudioProperties *props = file.audioProperties(); - if (!tags || !props) - return false; - //cout << "ARTIST=" << tags->artist().to8Bit(true) << "\n"; - //cout << "TITLE=" << tags->title().to8Bit(true) << "\n"; - //cout << "ALBUM=" << tags->album().to8Bit(true) << "\n"; - int length = props->length(); - if (!length) - return false; - string mbid = ExtractMusicBrainzTrackID(file.file()); - if (mbid.size() != 36 && !ignore_missing_mbid) - return false; - if (mbid.size() == 36) - cout << "MBID=" << mbid << "\n"; - cout << "LENGTH=" << length << "\n"; - cout << "BITRATE=" << props->bitrate() << "\n"; - return true; -} - -string ExtractExtension(const string &filename) -{ - size_t pos = filename.find_last_of('.'); - if (pos == string::npos) { - return string(); - } - return boost::to_upper_copy(filename.substr(pos + 1)); -} - -string EncodeFingerprint(const vector &fp) -{ - string res; - res.resize(fp.size()); - return res; -} - -bool ProcessFile(Chromaprint::Fingerprinter *fingerprinter, const string &filename, bool ignore_missing_mbid, int audio_length) -{ - if (!ReadTags(filename, ignore_missing_mbid)) - return false; - Decoder decoder(filename); - if (!decoder.Open()) - return false; - if (!fingerprinter->Start(decoder.SampleRate(), decoder.Channels())) - return false; - cerr << filename << "\n"; - cout << "FILENAME=" << filename << "\n"; - cout << "FORMAT=" << ExtractExtension(filename) << "\n"; - decoder.Decode(fingerprinter, audio_length); - vector fp = fingerprinter->Finish(); - /*cout << "FINGERPRINT1="; - for (int i = 0; i < fp.size(); i++) { - cout << fp[i] << ", "; - } - cout << "\n";*/ - cout << "FINGERPRINT=" << Chromaprint::Base64Encode(Chromaprint::CompressFingerprint(fp, kChromaprintAlgorithm)) << "\n\n"; - return true; -} - -int main(int argc, char **argv) -{ - if (argc < 2) { - cerr << "Usage: " << argv[0] << " [OPTIONS] FILE...\n"; - cerr << "Options:\n"; - cerr << " -nombid Do not require a MBID embedded in the file\n"; - cerr << " -since DATE Process only files modified since the given date\n"; - cerr << " -length SECONDS Length of the audio data used for fingerprinting (default 120)\n"; - return 1; - } - - string_vector files; - char *changed_since_str = NULL; - int audio_length = 120; - bool ignore_missing_mbid = false; - for (int i = 1; i < argc; i++) { - if (strcmp(argv[i], "-nombid") == 0) { - ignore_missing_mbid = true; - } - else if (strcmp(argv[i], "-since") == 0 && i + 1 < argc) { - changed_since_str = argv[++i]; - } - else if (strcmp(argv[i], "-length") == 0 && i + 1 < argc) { - audio_length = atoi(argv[++i]); - } - else { - files.push_back(argv[i]); - } - } - - time_t changed_since = 0; - if (changed_since_str) { - struct tm tm; - memset(&tm, 0, sizeof(tm)); - if (strptime(changed_since_str, "%Y-%m-%d %H:%M", &tm) == NULL) { - if (strptime(changed_since_str, "%Y-%m-%d", &tm) == NULL) { - cerr << "ERROR: Invalid date, the expected format is 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM'\n"; - return 1; - } - } - tm.tm_isdst = -1; - changed_since = mktime(&tm); - //cerr << "Calculating fingerprints for files in " << files << " that were changed since " << changed_since_str << "\n"; - } - else { - //cerr << "Calculating fingerprints for all files in " << files << "\n"; - } - - Chromaprint::Fingerprinter fingerprinter(Chromaprint::CreateFingerprinterConfiguration(kChromaprintAlgorithm)); - files = FindFiles(files, changed_since); - for (string_vector::iterator it = files.begin(); it != files.end(); it++) { - ProcessFile(&fingerprinter, *it, ignore_missing_mbid, audio_length); - } - - return 0; -} - diff --git a/3rdparty/chromaprint/tools/fpeval.cpp b/3rdparty/chromaprint/tools/fpeval.cpp deleted file mode 100644 index b003c7a2f..000000000 --- a/3rdparty/chromaprint/tools/fpeval.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "ext/ffmpeg_decoder.h" -#include "ext/image_utils.h" -#include "audio_processor.h" -#include "fingerprinter.h" -#include "image.h" -#include "integral_image.h" -#include "image_builder.h" -#include "utils.h" -#include "filter.h" -#include "lloyds.h" -#include "classifier.h" -#include "match.h" - -using namespace std; -using namespace Chromaprint; -namespace fs = boost::filesystem; - -typedef vector string_vector; -typedef vector double_vector; - -string_vector FindAudioFiles(const char *dirname) -{ - string_vector result; - fs::path path(dirname); - fs::directory_iterator end_iter; - for (fs::directory_iterator dir_iter(path); dir_iter != end_iter; ++dir_iter) { - if (fs::is_regular_file(dir_iter->status())) { - string filename = dir_iter->path().string(); - if (boost::ends_with(filename, ".mp3") || boost::ends_with(filename, ".wav")) { - result.push_back(filename); - } - } - } - sort(result.begin(), result.end()); - return result; -} - -vector GenerateFilePairs(const vector &files) -{ - string last_name; - vector result; - for (int i = 0; i < files.size(); i++) { - string name = fs::basename(files[i]); - name = name.substr(0, name.find_first_of('-')); - if (last_name != name) { - result.push_back(string_vector()); - last_name = name; - } - result.back().push_back(files[i]); - } - return result; -} - -vector MultiMapValues(const multimap &data, const int &key) -{ - pair::const_iterator, multimap::const_iterator> range = data.equal_range(key); - vector result; - for (multimap::const_iterator i = range.first; i != range.second; ++i) { - result.push_back((*i).second); - } - return result; -} - -static const int SAMPLE_RATE = 11025; -static const int FRAME_SIZE = 4096; -static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720; -static const int MIN_FREQ = 28; -static const int MAX_FREQ = 3520; -static const int MAX_FILTER_WIDTH = 16; -/*static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 2;// 2720; -static const int MIN_FREQ = 300; -static const int MAX_FREQ = 5300; -static const int MAX_FILTER_WIDTH = 20;*/ - -void PrintRate(const std::string &name, const std::vector &values, int scale) -{ - cout << name << " = ["; - for (int j = 0; j < 32; j++) { - double rate = double(values[j]) / scale; - if (j != 0) std::cout << ", "; - std::cout << rate; - } - cout << "]\n"; -} - -#define FP_TYPE_CHROMA 1 -#define FP_TYPE_CENTROID 2 -#define FP_TYPE FP_TYPE_CHROMA - -int main(int argc, char **argv) -{ - Chromaprint::Fingerprinter fingerprinter; - - vector files = FindAudioFiles(argv[1]); - vector< string > names[2]; - vector< vector > fingerprints[2]; - for (int i = 0; i < files.size(); i++) { - cout << " - " << files[i] << "\n"; - Decoder decoder(files[i]); - if (!decoder.Open()) { - cerr << "ERROR: " << decoder.LastError() << "\n"; - return 1; - } - fingerprinter.Start(decoder.SampleRate(), decoder.Channels()); - decoder.Decode(&fingerprinter, 60); - vector fp = fingerprinter.Finish(); - int orig = files[i].find("orig") != string::npos ? 1 : 0; - fingerprints[orig].push_back(fp); - names[orig].push_back(files[i]); - } - int num_files = files.size() / 2; - - typedef boost::multi_array DoubleArray2D; - - float total = 0.0f, diagonal = 0.0f; - DoubleArray2D confmatrix(boost::extents[num_files][num_files]); - for (int i = 0; i < num_files; i++) { - for (int j = 0; j < num_files; j++) { - float score = match_fingerprints(fingerprints[0][i], fingerprints[1][j]); - cout << " - " << names[0][i] << " / " << names[1][j] << " = " << score <<"\n"; - confmatrix[i][j] = score; - if (i == j) { - diagonal += score; - } - total += score; - } - } - - cout << "true positive: " << diagonal / num_files << "\n"; - cout << "false positive: " << (total - diagonal) / (num_files * num_files - num_files) << "\n"; - cout << "score: " << diagonal / total << "\n"; - return 0; -} - diff --git a/3rdparty/chromaprint/tools/fpsubmit.py b/3rdparty/chromaprint/tools/fpsubmit.py deleted file mode 100755 index 9bc2fb722..000000000 --- a/3rdparty/chromaprint/tools/fpsubmit.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python - -import time -import sys -import urllib2 -import urllib -import gzip -import socket -from cStringIO import StringIO -from optparse import OptionParser - - -usage = "usage: %prog [options] logfile" -parser = OptionParser(usage=usage) -parser.add_option("-a", "--api-key", dest="api_key", metavar="KEY", - help="your Acoustid API key (http://acoustid.org/api-key)") -parser.add_option("-b", "--batch-size", dest="batch_size", type="int", - default=50, metavar="SIZE", - help="how many fingerprints to submit in one request [default: %default]") -parser.add_option("--app-url", dest="app_url", type="string", - default='http://api.acoustid.org/submit', - help="how many fingerprints to submit in one request [default: %default]") -parser.add_option("--app-api-key", dest="app_api_key", type="string", default='5hOby2eZ', - help="application API key (needed only if you submit to a non-default URL)") -parser.add_option("-s", "--start", dest="start", type="int", - default=1, metavar="SIZE", - help="start with the Nth entry from the log file [default: %default]") - -(options, args) = parser.parse_args() -if not options.api_key: - parser.error("no API key specified") -if len(args) != 1: - parser.error("no log file specified") - - -USER_API_KEY = options.api_key -CLIENT_API_KEY = options.app_api_key -API_URL = options.app_url -BATCH_SIZE = options.batch_size - - -def read_log_file(input): - group = {} - for line in input: - line = line.strip() - if not line: - if group: - yield group - group = {} - continue - name, value = line.split('=', 1) - group[name] = value - if group: - yield group - - -def encode_params(data): - encoded_body = StringIO() - encoded_file = gzip.GzipFile(mode='w', fileobj=encoded_body) - encoded_file.write(urllib.urlencode(data)) - encoded_file.close() - return encoded_body.getvalue() - - -def submit_data(i, entries): - if not entries: - return True - params = { 'user': USER_API_KEY, 'client': CLIENT_API_KEY } - print 'Submitting... (entries from %d to %d)' % (i, i + len(entries) - 1) - i = 0 - for entry in [e for e in entries if e['LENGTH'] >= 40 and len(e['FINGERPRINT'])>100]: - if 'MBID' not in entry and 'PUID' not in entry or int(entry.get('LENGTH', '0')) <= 0: - continue - if 'MBID' in entry: - print ' MBID ', entry['MBID'], entry['FINGERPRINT'][:20] + '...' - for mbid in entry['MBID'].split(','): - params['mbid.%d' % i] = mbid - if 'PUID' in entry: - print ' PUID ', entry['PUID'], entry['FINGERPRINT'][:20] + '...' - params['puid.%d' % i] = entry['PUID'] - params['fingerprint.%d' % i] = entry['FINGERPRINT'] - params['length.%d' % i] = entry['LENGTH'] - if 'BITRATE' in entry: - params['bitrate.%d' % i] = entry['BITRATE'] - if 'FORMAT' in entry: - params['format.%d' % i] = entry['FORMAT'] - i += 1 - data = encode_params(params) - request = urllib2.Request(API_URL, data, headers={'Content-Encoding': 'gzip'}) - try: - urllib2.urlopen(request) - except urllib2.HTTPError, e: - print e - for line in e.readlines(): - print line.rstrip() - return False - except urllib2.URLError, e: - print e - return False - except socket.error, e: - print e - return False - print 'OK' - return True - - -batch = [] -i = options.start -j = 0 -for entry in read_log_file(open(args[0]) if args[0] != '-' else sys.stdin): - j += 1 - if j < options.start: - continue - batch.append(entry) - if len(batch) >= BATCH_SIZE: - submit_data(i, batch) - i = j - batch = [] - time.sleep(0.1) -submit_data(i, batch) - diff --git a/3rdparty/chromaprint/tools/learn_filters.cpp b/3rdparty/chromaprint/tools/learn_filters.cpp deleted file mode 100644 index 01663abae..000000000 --- a/3rdparty/chromaprint/tools/learn_filters.cpp +++ /dev/null @@ -1,396 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "ext/ffmpeg_decoder.h" -#include "ext/image_utils.h" -#include "audio_processor.h" -#include "chroma.h" -#include "spectral_centroid.h" -#include "chroma_normalizer.h" -#include "chroma_resampler.h" -#include "chroma_filter.h" -#include "fft.h" -#include "audio_processor.h" -#include "image.h" -#include "integral_image.h" -#include "image_builder.h" -#include "utils.h" -#include "filter.h" -#include "lloyds.h" -#include "classifier.h" - -using namespace std; -using namespace Chromaprint; -namespace fs = boost::filesystem; - -typedef vector string_vector; -typedef vector double_vector; - -string_vector FindAudioFiles(const char *dirname) -{ - string_vector result; - fs::path path(dirname); - fs::directory_iterator end_iter; - for (fs::directory_iterator dir_iter(path); dir_iter != end_iter; ++dir_iter) { - if (fs::is_regular_file(dir_iter->status())) { - string filename = dir_iter->path().string(); - if (boost::ends_with(filename, ".mp3") || boost::ends_with(filename, ".wma") || boost::ends_with(filename, ".wav")) { - result.push_back(filename); - } - } - } - sort(result.begin(), result.end()); - return result; -} - -vector GenerateFilePairs(const vector &files) -{ - string last_name; - vector result; - for (int i = 0; i < files.size(); i++) { - string name = fs::basename(files[i]); - name = name.substr(0, name.find_first_of('-')); - if (last_name != name) { - result.push_back(string_vector()); - last_name = name; - } - result.back().push_back(files[i]); - } - return result; -} - -vector MultiMapValues(const multimap &data, const int &key) -{ - pair::const_iterator, multimap::const_iterator> range = data.equal_range(key); - vector result; - for (multimap::const_iterator i = range.first; i != range.second; ++i) { - result.push_back((*i).second); - } - return result; -} - -static const int SAMPLE_RATE = 11025; -static const int FRAME_SIZE = 4096; -static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720; -static const int MIN_FREQ = 28; -static const int MAX_FREQ = 3520; -static const int MAX_FILTER_WIDTH = 16; -/*static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 2;// 2720; -static const int MIN_FREQ = 300; -static const int MAX_FREQ = 5300; -static const int MAX_FILTER_WIDTH = 20;*/ - -static const int TRAINING_SET_SIZE = 60000; - -void PrintRate(const std::string &name, const std::vector &values, int scale) -{ - cout << name << " = ["; - for (int j = 0; j < 32; j++) { - double rate = double(values[j]) / scale; - if (j != 0) std::cout << ", "; - std::cout << rate; - } - cout << "]\n"; -} - -#define FP_TYPE_CHROMA 1 -#define FP_TYPE_CENTROID 2 -#define FP_TYPE FP_TYPE_CHROMA - -int main(int argc, char **argv) -{ - Chromaprint::ImageBuilder image_builder; -#if FP_TYPE == FP_TYPE_CHROMA - Chromaprint::ChromaNormalizer chroma_normalizer(&image_builder); - static const double kChromaFilterCoeffs[] = { 0.25, 0.75, 1.0, 0.75, 0.25 }; - Chromaprint::ChromaFilter chroma_filter(kChromaFilterCoeffs, 5, &chroma_normalizer); - Chromaprint::Chroma chroma(MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &chroma_filter); - //chroma.set_interpolate(true); - Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, &chroma); -#elif FP_TYPE == FP_TYPE_CHROMA - Chromaprint::SpectralCentroid centroid(16, MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &image_builder); - Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, ¢roid); -#endif - Chromaprint::AudioProcessor processor(SAMPLE_RATE, &fft); - - cout << "Loading audio files\n"; - vector files = GenerateFilePairs(FindAudioFiles(argv[1])); - vector groups; - multimap reverse_groups; - vector images; - vector integral_images; - for (int i = 0; i < files.size(); i++) { - //cout << i << ".\n"; - for (int j = 0; j < files[i].size(); j++) { - cout << " - " << files[i][j] << "\n"; - Decoder decoder(files[i][j]); - if (!decoder.Open()) { - cerr << "ERROR: " << decoder.LastError() << "\n"; - return 1; - } -#if FP_TYPE == FP_TYPE_CHROMA - Image *image = new Image(12); -#elif FP_TYPE == FP_TYPE_CENTROID - Image *image = new Image(16); -#endif - processor.Reset(decoder.SampleRate(), decoder.Channels()); - fft.Reset(); -#if FP_TYPE == FP_TYPE_CHROMA - chroma.Reset(); - chroma_filter.Reset(); - chroma_normalizer.Reset(); -#elif FP_TYPE == FP_TYPE_CENTROID - centroid.Reset(); -#endif - image_builder.Reset(image); - decoder.Decode(&processor); - processor.Flush(); - //ExportTextImage(image, files[i][j] + ".img.txt"); - //Chromaprint::ExportImage(image_builder.image(), files[i][j] + ".img.png"); - reverse_groups.insert(make_pair(i, images.size())); - groups.push_back(i); - images.push_back(image); - IntegralImage *int_image = new IntegralImage(image) ; - // ExportTextImage(int_image, files[i][j] + ".int_img.txt"); - integral_images.push_back(int_image); - //ExportTextImage(int_image, files[i][j] + ".img.txt"); - // return 1; - } - cout << images.size() << "\r"; - cout.flush(); - } - - cout << "Training data set:\n"; - cout << " - File groups: " << files.size() << "\n"; - cout << " - Files: " << images.size() << "\n"; - files.clear(); - - bool labels[TRAINING_SET_SIZE]; - int data1[TRAINING_SET_SIZE]; - int data2[TRAINING_SET_SIZE]; - int data1_pos[TRAINING_SET_SIZE]; - int data2_pos[TRAINING_SET_SIZE]; - - int i = 0; - srand(3); - // Find matching pairs - for (; i < TRAINING_SET_SIZE / 2; i++) { - int x1 = rand() % images.size(); - vector group = MultiMapValues(reverse_groups, groups[x1]); - int x2; - do { - x2 = group[rand() % group.size()]; - } while (x1 == x2); - size_t min_length = min(images[x1]->NumRows(), images[x2]->NumRows()); - int pos = rand() % (min_length - 30); - //cout << "+ " << x1 << " " << x2 << " - " << pos << "\n"; - data1[i] = x1; - data2[i] = x2; - data1_pos[i] = pos; - data2_pos[i] = pos; - labels[i] = true; - } - // Find non-matching pairs - for (; i < TRAINING_SET_SIZE; i++) { - int x2, x1 = rand() % images.size(); - int pos2, pos1 = rand() % (images[x1]->NumRows() - 30); - vector group = MultiMapValues(reverse_groups, groups[x1]); - set group_set(group.begin(), group.end()); - do { - x2 = rand() % images.size(); - pos2 = rand() % (images[x2]->NumRows() - 30); - } while (group_set.count(x2) && abs(pos1 - pos2) < 50); - //cout << "- " << x1 << " " << x2 << " - " << pos1 << " " << pos2 << "\n"; - data1[i] = x1; - data2[i] = x2; - data1_pos[i] = pos1; - data2_pos[i] = pos2; - labels[i] = false; - } - - const float maxWidth = 16.0; - const float widthScale = 1.0; - const float widthIncrement = 1.0; - - const int numFilters = 6; - const int maxHeight = images[0]->NumColumns(); - const int filterWidthInc[] = { 1, 1, 2, 2, 1, 3 }; - const int filterHeightInc[] = { 1, 2, 1, 2, 3, 1 }; - const int kNumCandidateQuantizers = 24; - - double weights[TRAINING_SET_SIZE]; - for (int i = 0; i < TRAINING_SET_SIZE; i++) { - weights[i] = 1.0 / TRAINING_SET_SIZE; - } - - cout << "Computing filter responses\n"; - std::vector filters; - double *values_buffer = new double[100 * TRAINING_SET_SIZE * 2]; - - Filter flt; - FILE *f = fopen("filters.tmp", "wb"); - for (int filter = 0; filter < numFilters; filter++) { - flt.set_type(filter); - for (int y = 0; y < maxHeight; y++) { - flt.set_y(y); - for (int h = filterHeightInc[filter]; h < maxHeight - y; h += filterHeightInc[filter]) { - flt.set_height(h); - int pw = 0; - for (int wf = filterWidthInc[filter]; wf <= maxWidth; wf += filterWidthInc[filter]) { - int w = wf; - if (pw == w) - continue; - flt.set_width(w); - fill(values_buffer, values_buffer + TRAINING_SET_SIZE * 2, 0.0); - for (int i = 0; i < TRAINING_SET_SIZE; i++) { - double value1 = flt.Apply(integral_images[data1[i]], data1_pos[i]); - double value2 = flt.Apply(integral_images[data2[i]], data2_pos[i]); - //cout << flt << " " << value1 << " [" << data1[i] << ":" << data1_pos[i] << "] " << value2 << " [" << data2[i] << ":" << data2_pos[i] << "]\n"; - values_buffer[2*i+0] = value1; - values_buffer[2*i+1] = value2; - } - fwrite(values_buffer, sizeof(double), TRAINING_SET_SIZE * 2, f); - filters.push_back(flt); - } - } - } - } - cout << "Filters: " << filters.size() << "\n"; - - fclose(f); - f = fopen("filters.tmp", "rb"); - - cout << "Computing quantizers\n"; - double *all_candidate_quantizers = new double[filters.size() * kNumCandidateQuantizers]; - double *quantizer_ptr = all_candidate_quantizers; - fseek(f, 0, SEEK_SET); - double *values_ptr = values_buffer + 100 * TRAINING_SET_SIZE * 2; - for (int filter_i = 0; filter_i < filters.size(); filter_i++) { - int num_values = TRAINING_SET_SIZE * 2; - if (values_ptr >= values_buffer + 100 * TRAINING_SET_SIZE * 2) { - fread(values_buffer, sizeof(double), 100 * num_values, f); - values_ptr = values_buffer; - } - double_vector candidate_quantizers = lloyds(values_ptr, values_ptr + num_values, kNumCandidateQuantizers); - copy(candidate_quantizers.begin(), candidate_quantizers.end(), quantizer_ptr); - quantizer_ptr += kNumCandidateQuantizers; - values_ptr += num_values; - cout << filter_i << "\r"; - cout.flush(); - } - - cout << "Running AdaBoost\n"; - vector best_classifiers; - vector best_classifiers_alpha; - - int iteration = 0; -next_iteration: - - double min_error = 1.0; - Classifier best_classifier; - boost::dynamic_bitset<> best_results(TRAINING_SET_SIZE); - fseek(f, 0, SEEK_SET); - quantizer_ptr = all_candidate_quantizers; - values_ptr = values_buffer + 100 * TRAINING_SET_SIZE * 2; - for (int filter_i = 0; filter_i < filters.size(); filter_i++) { - std::size_t num_values = TRAINING_SET_SIZE * 2; - if (values_ptr >= values_buffer + 100 * TRAINING_SET_SIZE * 2) { - fread(values_buffer, sizeof(double), 100 * num_values, f); - values_ptr = values_buffer; - } - - Quantizer quantizer(0.0, 0.0, 0.0); - for (int ti0 = 0; ti0 < kNumCandidateQuantizers - 3; ti0++) { - quantizer.set_t0(quantizer_ptr[ti0]); - for (int ti1 = ti0 + 1; ti1 < kNumCandidateQuantizers - 2; ti1++) { - quantizer.set_t1(quantizer_ptr[ti1]); - for (int ti2 = ti1 + 1; ti2 < kNumCandidateQuantizers - 1; ti2++) { - quantizer.set_t2(quantizer_ptr[ti2]); - double error = 0.0; - for (int i = 0; i < TRAINING_SET_SIZE; i++) { - int q1 = quantizer.Quantize(values_ptr[i*2 + 0]); - int q2 = quantizer.Quantize(values_ptr[i*2 + 1]); - bool match = (q1 == q2) == labels[i]; - if (!match) { - error += weights[i]; - } - } - if (error < min_error) { - best_classifier = Classifier(filters[filter_i], quantizer); - min_error = error; - for (int i = 0; i < TRAINING_SET_SIZE; i++) { - int q1 = quantizer.Quantize(values_ptr[i*2 + 0]); - int q2 = quantizer.Quantize(values_ptr[i*2 + 1]); - bool match = (q1 == q2) == labels[i]; - best_results[i] = match; - } - } - } - } - } - quantizer_ptr += kNumCandidateQuantizers; - values_ptr += num_values; - cout << filter_i << " [" << min_error << "] \r"; - cout.flush(); - } - - double weight_sum = 0.0; - double alpha = 0.5 * log((1.0 - min_error) / min_error); - for (int i = 0; i < TRAINING_SET_SIZE; i++) { - weights[i] *= exp(-alpha * (best_results[i] ? 1.0 : -1.0)); - weight_sum += weights[i]; - } - for (int i = 0; i < TRAINING_SET_SIZE; i++) { - weights[i] /= weight_sum; - } - - best_classifiers.push_back(best_classifier); - best_classifiers_alpha.push_back(alpha); - - int wrong = 0; - int counts[2]; - counts[0] = 0; - counts[1] = 0; - std::vector bit_tp(32, 0); - std::vector bit_fp(32, 0); - for (int i = 0; i < TRAINING_SET_SIZE; i++) { - double value = 0.0; - int bit_error = 0; - for (int j = 0; j < best_classifiers.size(); j++) { - int q1 = best_classifiers[j].Classify(integral_images[data1[i]], data1_pos[i]); - int q2 = best_classifiers[j].Classify(integral_images[data2[i]], data2_pos[i]); - int e = abs(q1 - q2); - bit_error += e == 3 ? 1 : e; - value += best_classifiers_alpha[j] * (q1 == q2 ? 1.0 : -1.0); - } - bool match = value > 0.0; - counts[labels[i]]++; - if (labels[i] != match) { - wrong += 1.0; - } - for (int j = 0; j < 32; j++) { - bool bit_match = bit_error <= j; - if (labels[i] && bit_match) { - bit_tp[j]++; - } - if (!labels[i] && bit_match) { - bit_fp[j]++; - } - } - } - - ++iteration; - cout << iteration << ". best classifier is " << best_classifier << " with error " << min_error << " (alpha " << alpha << "), final error is " << double(wrong) / TRAINING_SET_SIZE << "\n"; - PrintRate("TP", bit_tp, counts[1]); - PrintRate("FP", bit_fp, counts[0]); - - if (iteration < 16) - goto next_iteration; - - return 0; -} - diff --git a/3rdparty/chromaprint/tools/match.h b/3rdparty/chromaprint/tools/match.h deleted file mode 100644 index aabe61673..000000000 --- a/3rdparty/chromaprint/tools/match.h +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include - -/* fingerprint matcher settings */ -#define ACOUSTID_MAX_BIT_ERROR 2 -#define ACOUSTID_MAX_ALIGN_OFFSET 120 - -#define BITCOUNT(x) __builtin_popcount(x) - -inline float -match_fingerprints(const std::vector &a, const std::vector &b) -{ - int i, j, topcount; - int maxsize = std::max(a.size(), b.size()); - int numcounts = maxsize * 2 + 1; - int *counts = (int*)malloc(sizeof(int) * numcounts); - - memset(counts, 0, sizeof(int) * numcounts); - for (i = 0; i < a.size(); i++) { - int jbegin = std::max(0, i - ACOUSTID_MAX_ALIGN_OFFSET); - int jend = std::min(b.size(), size_t(i + ACOUSTID_MAX_ALIGN_OFFSET)); - for (j = jbegin; j < jend; j++) { - int biterror = BITCOUNT(a[i] ^ b[j]); - if (biterror <= ACOUSTID_MAX_BIT_ERROR) { - int offset = i - j + maxsize; - counts[offset]++; - } - } - } - - topcount = 0; - for (i = 0; i < numcounts; i++) { - if (counts[i] > topcount) { - topcount = counts[i]; - } - } - - free(counts); - - return (float)topcount / std::min(a.size(), b.size()); -} diff --git a/3rdparty/chromaprint/tools/misc/prepare-128mp3.sh b/3rdparty/chromaprint/tools/misc/prepare-128mp3.sh deleted file mode 100755 index b3b0c3573..000000000 --- a/3rdparty/chromaprint/tools/misc/prepare-128mp3.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -for FILE in `ls *-orig.wav`; do - TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-128mp3.mp3/'` - NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-128mp3.wav/'` - if [ ! -f $NEWFILE ]; then - rm -f $NEWFILE - ffmpeg -i $FILE -ab 128000 $TMPNEWFILE - ffmpeg -i $TMPNEWFILE $NEWFILE - rm -f $TMPNEWFILE - fi -done - diff --git a/3rdparty/chromaprint/tools/misc/prepare-32mp3.sh b/3rdparty/chromaprint/tools/misc/prepare-32mp3.sh deleted file mode 100755 index 18a7ab24e..000000000 --- a/3rdparty/chromaprint/tools/misc/prepare-32mp3.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -for FILE in `ls *-orig.wav`; do - TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-32mp3.mp3/'` - NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-32mp3.wav/'` - if [ ! -f $NEWFILE ]; then - rm -f $NEWFILE - ffmpeg -i $FILE -ab 32000 $TMPNEWFILE - ffmpeg -i $TMPNEWFILE $NEWFILE - rm -f $TMPNEWFILE - fi -done - diff --git a/3rdparty/chromaprint/tools/misc/prepare-64mp3.sh b/3rdparty/chromaprint/tools/misc/prepare-64mp3.sh deleted file mode 100755 index 23f1a86ce..000000000 --- a/3rdparty/chromaprint/tools/misc/prepare-64mp3.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -for FILE in `ls *-orig.wav`; do - TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-64mp3.mp3/'` - NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-64mp3.wav/'` - if [ ! -f $NEWFILE ]; then - rm -f $NEWFILE - ffmpeg -i $FILE -ab 64000 $TMPNEWFILE - ffmpeg -i $TMPNEWFILE $NEWFILE - rm -f $TMPNEWFILE - fi -done - diff --git a/3rdparty/chromaprint/tools/misc/prepare-64wma.sh b/3rdparty/chromaprint/tools/misc/prepare-64wma.sh deleted file mode 100755 index f99d5f441..000000000 --- a/3rdparty/chromaprint/tools/misc/prepare-64wma.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -for FILE in `ls *-orig.wav`; do - TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-64wma.wma/'` - NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-64wma.wav/'` - if [ ! -f $NEWFILE ]; then - rm -f $NEWFILE - ffmpeg -i $FILE -ab 64000 -acodec wmav2 $TMPNEWFILE - ffmpeg -i $TMPNEWFILE $NEWFILE - rm -f $TMPNEWFILE - fi -done - diff --git a/3rdparty/chromaprint/tools/misc/prepare-gain.sh b/3rdparty/chromaprint/tools/misc/prepare-gain.sh deleted file mode 100755 index 7bae2c07c..000000000 --- a/3rdparty/chromaprint/tools/misc/prepare-gain.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -for FILE in `ls *-orig.wav`; do - TMP1FILE=`echo $FILE | perl -pe 's/-orig\..*$/-tmp.wav/'` - TMP2FILE=`echo $FILE | perl -pe 's/-orig\..*$/-tmp2.wav/'` - TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-gain.wma/'` - NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-gain.wav/'` - if [ ! -f $NEWFILE ]; then - rm -f $NEWFILE $TMP1FILE $TMP2FILE - ffmpeg -i $FILE $TMP1FILE - sox $TMP1FILE $TMP2FILE gain -n -10 - ffmpeg -i $TMP2FILE -ab 128000 -acodec wmav2 $TMPNEWFILE - ffmpeg -i $TMPNEWFILE $NEWFILE - rm -f $TMP1FILE $TMP2FILE $TMPNEWFILE - fi -done - diff --git a/3rdparty/chromaprint/tools/misc/prepare-resample.sh b/3rdparty/chromaprint/tools/misc/prepare-resample.sh deleted file mode 100755 index 0bb01b854..000000000 --- a/3rdparty/chromaprint/tools/misc/prepare-resample.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -for FILE in `ls *-orig.wav`; do - TMP1FILE=`echo $FILE | perl -pe 's/-orig\..*$/-tmp.wav/'` - TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-resample.wma/'` - NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-resample.wav/'` - if [ ! -f $NEWFILE ]; then - rm -f $NEWFILE $TMP1FILE $TMPNEWFILE - sox $FILE $TMP1FILE rate -l 8k - ffmpeg -i $TMP1FILE -ab 128000 -acodec wmav2 $TMPNEWFILE - ffmpeg -i $TMPNEWFILE $NEWFILE - rm -f $TMP1FILE $TMPNEWFILE - fi -done - diff --git a/3rdparty/chromaprint/tools/misc/prepare-wav.sh b/3rdparty/chromaprint/tools/misc/prepare-wav.sh deleted file mode 100755 index d0d7c0884..000000000 --- a/3rdparty/chromaprint/tools/misc/prepare-wav.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -for FILE in `ls *.{mp3,wma,ogg}`; do - NEWFILE=`echo $FILE | perl -pe 's/\..*$/.wav/'` - rm -f $NEWFILE - ffmpeg -i $FILE $NEWFILE - rm -f $FILE -done - diff --git a/3rdparty/chromaprint/tools/misc/prepare.sh b/3rdparty/chromaprint/tools/misc/prepare.sh deleted file mode 100755 index 869f1b81d..000000000 --- a/3rdparty/chromaprint/tools/misc/prepare.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -cp orig/*.wav . -./prepare-32mp3.sh -./prepare-64mp3.sh -./prepare-128mp3.sh -./prepare-64wma.sh -./prepare-gain.sh -./prepare-wav.sh diff --git a/3rdparty/chromaprint/tools/resample.cpp b/3rdparty/chromaprint/tools/resample.cpp deleted file mode 100644 index 77a18f364..000000000 --- a/3rdparty/chromaprint/tools/resample.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include - -using namespace std; - -#include "ext/ffmpeg_decoder.h" -#include "ext/audio_dumper.h" -#include "audio_processor.h" - -int main(int argc, char **argv) -{ - if (argc < 2) { - cerr << "Usage: " << argv[0] << " FILENAME\n"; - return 1; - } - - string file_name(argv[1]); - cout << "Loading file " << file_name << "\n"; - - Decoder decoder(file_name); - if (!decoder.Open()) { - cerr << "ERROR: " << decoder.LastError() << "\n"; - return 2; - } - - AudioDumper dumper("resampled.raw"); - Chromaprint::AudioProcessor processor(11025, &dumper); - processor.Reset(decoder.SampleRate(), decoder.Channels()); - - decoder.Decode(&processor); - processor.Flush(); - - return 0; -} - diff --git a/3rdparty/chromaprint/tools/spectrogram.cpp b/3rdparty/chromaprint/tools/spectrogram.cpp deleted file mode 100644 index 8fe4a5793..000000000 --- a/3rdparty/chromaprint/tools/spectrogram.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include - -using namespace std; - -#include "ext/ffmpeg_decoder.h" -#include "ext/audio_dumper.h" -#include "audio_processor.h" -#include "chroma.h" -#include "spectrum.h" -#include "chroma_normalizer.h" -#include "chroma_resampler.h" -#include "chroma_filter.h" -#include "fft.h" -#include "audio_processor.h" -#include "image.h" -#include "image_builder.h" -#include "utils.h" -#include "ext/image_utils.h" - -static const int SAMPLE_RATE = 11025; -static const int FRAME_SIZE = 4096; -static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720; -static const int MIN_FREQ = 28; -static const int MAX_FREQ = 3520; -static const int MAX_FILTER_WIDTH = 20; - -static const int kChromaFilterSize = 5; -static const double kChromaFilterCoefficients[] = { 0.25, 0.75, 1.0, 0.75, 0.25 }; - -int main(int argc, char **argv) -{ - if (argc < 3) { - cerr << "Usage: " << argv[0] << " AUDIOFILE IMAGEFILE\n"; - return 1; - } - - string file_name(argv[1]); - cout << "Loading file " << file_name << "\n"; - - Decoder decoder(file_name); - if (!decoder.Open()) { - cerr << "ERROR: " << decoder.LastError() << "\n"; - return 2; - } - - const int numBands = 72; - Chromaprint::Image image(numBands); - Chromaprint::ImageBuilder image_builder(&image); - Chromaprint::Spectrum chroma(numBands, MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &image_builder); - Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, &chroma); - Chromaprint::AudioProcessor processor(SAMPLE_RATE, &fft); - - processor.Reset(decoder.SampleRate(), decoder.Channels()); - decoder.Decode(&processor); - processor.Flush(); - - //Chromaprint::ExportTextImage(&image, argv[2]); - Chromaprint::ExportImage(&image, argv[2], 0.5); - - return 0; -} - From 842cfadf6b8c12c84bb81376e43b971dbdc903ae Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sat, 7 Jan 2012 15:25:39 +0000 Subject: [PATCH 30/40] Use the system version of libchromaprint if available (cherry picked from commit d17629586f43da51450166347164eeda16592880) --- CMakeLists.txt | 9 ++++++++- src/CMakeLists.txt | 3 ++- src/musicbrainz/chromaprinter.cpp | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 297498430..ddc3fa895 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,7 @@ pkg_check_modules(INDICATEQT indicate-qt) pkg_check_modules(SPOTIFY libspotify>=10.1.16) pkg_check_modules(CDIO libcdio) pkg_check_modules(QCA qca2) +pkg_check_modules(CHROMAPRINT libchromaprint) if (WIN32) find_package(ZLIB REQUIRED) @@ -355,6 +356,13 @@ if(GMOCK_INCLUDE_DIRS) endif(GTEST_INCLUDE_DIRS) endif(GMOCK_INCLUDE_DIRS) +# Use our 3rdparty chromaprint if a system one wasn't found +if(NOT CHROMAPRINT_FOUND) + add_subdirectory(3rdparty/chromaprint) + set(CHROMAPRINT_LIBRARIES chromaprint_p) + set(CHROMAPRINT_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/3rdparty/chromaprint/src) +endif(NOT CHROMAPRINT_FOUND) + # Subdirectories add_subdirectory(src) if (WIN32) @@ -365,7 +373,6 @@ add_subdirectory(3rdparty/universalchardet) add_subdirectory(tests) add_subdirectory(dist) add_subdirectory(tools/ultimate_lyrics_parser) -add_subdirectory(3rdparty/chromaprint) option(WITH_DEBIAN OFF) if(WITH_DEBIAN) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 70b89ae04..71d567678 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,7 @@ include_directories(${QTSINGLEAPPLICATION_INCLUDE_DIRS}) include_directories(${QTIOCOMPRESSOR_INCLUDE_DIRS}) include_directories(${QXT_INCLUDE_DIRS}) include_directories(${ECHONEST_INCLUDE_DIRS}) +include_directories(${CHROMAPRINT_INCLUDE_DIRS}) find_package(OpenGL) include_directories(${OPENGL_INCLUDE_DIR}) @@ -960,8 +961,8 @@ add_dependencies(clementine_lib pot) target_link_libraries(clementine_lib chardet - chromaprint_p sha2 + ${CHROMAPRINT_LIBRARIES} ${ECHONEST_LIBRARIES} ${GOBJECT_LIBRARIES} ${GLIB_LIBRARIES} diff --git a/src/musicbrainz/chromaprinter.cpp b/src/musicbrainz/chromaprinter.cpp index 0be12c82e..25e56e189 100644 --- a/src/musicbrainz/chromaprinter.cpp +++ b/src/musicbrainz/chromaprinter.cpp @@ -22,7 +22,7 @@ #include #include -#include "3rdparty/chromaprint/src/chromaprint.h" +#include #include "core/logging.h" #include "core/timeconstants.h" From 5e231caf3e61fd6928c6761cd5f45cedb09ac82a Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sat, 7 Jan 2012 15:49:02 +0000 Subject: [PATCH 31/40] Add chromaprint/fftw dependencies to the debian control and rpm spec files (cherry picked from commit ae8ac239bfbb29ecc2592bc0aed63d89bd1953b1) --- debian/control | 3 ++- dist/clementine.spec.in | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/control b/debian/control index 4171d77da..aa2960932 100644 --- a/debian/control +++ b/debian/control @@ -30,7 +30,8 @@ Build-Depends: debhelper (>= 7), libqjson-dev, protobuf-compiler, libprotobuf-dev, - libqca2-dev + libqca2-dev, + libchromaprint-dev | libfftw3-dev Standards-Version: 3.8.1 Homepage: http://www.clementine-player.org/ diff --git a/dist/clementine.spec.in b/dist/clementine.spec.in index f9ed876cf..59983398c 100644 --- a/dist/clementine.spec.in +++ b/dist/clementine.spec.in @@ -14,7 +14,7 @@ BuildRequires: qt4-devel boost-devel gcc-c++ glew-devel libgpod-devel BuildRequires: cmake gstreamer-devel gstreamer-plugins-base-devel BuildRequires: libimobiledevice-devel libplist-devel usbmuxd-devel BuildRequires: libmtp-devel protobuf-devel protobuf-compiler libcdio-devel -BuildRequires: qjson-devel qca2-devel +BuildRequires: qjson-devel qca2-devel fftw-devel Requires: libgpod protobuf-lite libcdio qjson qca-ossl From a4944a83ddeb34dee8965a1045d662dee5ee79fb Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sat, 7 Jan 2012 17:29:35 +0000 Subject: [PATCH 32/40] Fix linking to chromaprint on Windows (cherry picked from commit 6f3df9bd5f62ecfff9f1ee5831e07745014b7a4f) --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ddc3fa895..3010ff53e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -361,6 +361,10 @@ if(NOT CHROMAPRINT_FOUND) add_subdirectory(3rdparty/chromaprint) set(CHROMAPRINT_LIBRARIES chromaprint_p) set(CHROMAPRINT_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/3rdparty/chromaprint/src) + + if(WIN32) + add_definitions(-DCHROMAPRINT_NODLL) + endif(WIN32) endif(NOT CHROMAPRINT_FOUND) # Subdirectories From dea9fbec952176837eb24d00ec7a9f17e818045b Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sat, 7 Jan 2012 21:51:02 +0000 Subject: [PATCH 33/40] Musicbrainz tagging improvements: * Fix a bug where the song title would be used for the album field * Get the album's year as well * Include all releases for a song in the results list * Remove duplicate albums * Sort results (cherry picked from commit e9c0b4bd69f96e99af825ec1839f456702f3bbf1) --- src/core/songloader.cpp | 1 + src/core/utilities.cpp | 12 +++++ src/core/utilities.h | 7 +++ src/devices/cddadevice.cpp | 3 +- src/internet/somafmservice.cpp | 17 +------ src/internet/somafmservice.h | 1 - src/musicbrainz/musicbrainzclient.cpp | 64 +++++++++++++++++++-------- src/musicbrainz/musicbrainzclient.h | 59 ++++++++++++++++++++++-- src/musicbrainz/tagfetcher.cpp | 1 + src/playlistparsers/xmlparser.cpp | 17 ------- src/playlistparsers/xmlparser.h | 1 - src/ui/trackselectiondialog.cpp | 12 ++--- src/ui/trackselectiondialog.ui | 9 +++- 13 files changed, 141 insertions(+), 63 deletions(-) diff --git a/src/core/songloader.cpp b/src/core/songloader.cpp index 29d8ad975..d4db3230d 100644 --- a/src/core/songloader.cpp +++ b/src/core/songloader.cpp @@ -201,6 +201,7 @@ void SongLoader::AudioCDTagsLoaded(const QString& artist, const QString& album, song.set_title(ret.title_); song.set_length_nanosec(ret.duration_msec_ * kNsecPerMsec); song.set_track(track_number); + song.set_year(ret.year_); // We need to set url: that's how playlist will find the correct item to update song.set_url(QUrl(QString("cdda://%1").arg(track_number++))); songs_ << song; diff --git a/src/core/utilities.cpp b/src/core/utilities.cpp index 9808de9d2..9a5748e3f 100644 --- a/src/core/utilities.cpp +++ b/src/core/utilities.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -383,6 +384,17 @@ quint16 PickUnusedPort() { } } +void ConsumeCurrentElement(QXmlStreamReader* reader) { + int level = 1; + while (level != 0 && !reader->atEnd()) { + switch (reader->readNext()) { + case QXmlStreamReader::StartElement: ++level; break; + case QXmlStreamReader::EndElement: --level; break; + default: break; + } + } +} + } // namespace Utilities diff --git a/src/core/utilities.h b/src/core/utilities.h index 3c39f0817..bbc6105de 100644 --- a/src/core/utilities.h +++ b/src/core/utilities.h @@ -29,6 +29,7 @@ class QIODevice; class QMouseEvent; +class QXmlStreamReader; namespace Utilities { QString PrettyTime(int seconds); @@ -75,6 +76,12 @@ namespace Utilities { bool IsMouseEventInWidget(const QMouseEvent* e, const QWidget* widget); + // Reads all children of the current element, and returns with the stream + // reader either on the EndElement for the current element, or the end of the + // file - whichever came first. + void ConsumeCurrentElement(QXmlStreamReader* reader); + + enum ConfigPath { Path_Root, Path_AlbumCovers, diff --git a/src/devices/cddadevice.cpp b/src/devices/cddadevice.cpp index b513c9209..6a2686cd1 100644 --- a/src/devices/cddadevice.cpp +++ b/src/devices/cddadevice.cpp @@ -144,8 +144,9 @@ void CddaDevice::AudioCDTagsLoaded(const QString& artist, const QString& album, song.set_album(album); song.set_title(ret.title_); song.set_length_nanosec(ret.duration_msec_ * kNsecPerMsec); - song.set_id(track_number); song.set_track(track_number); + song.set_year(ret.year_); + song.set_id(track_number); // We need to set url: that's how playlist will find the correct item to update song.set_url(QUrl(QString("cdda://%1/%2").arg(unique_id()).arg(track_number++))); songs << song; diff --git a/src/internet/somafmservice.cpp b/src/internet/somafmservice.cpp index aafa4df0b..672228cc0 100644 --- a/src/internet/somafmservice.cpp +++ b/src/internet/somafmservice.cpp @@ -23,6 +23,7 @@ #include "core/network.h" #include "core/player.h" #include "core/taskmanager.h" +#include "core/utilities.h" #include "globalsearch/globalsearch.h" #include "globalsearch/somafmsearchprovider.h" #include "ui/iconloader.h" @@ -151,7 +152,7 @@ void SomaFMService::ReadChannel(QXmlStreamReader& reader, StreamList* ret) { stream.url_ = url; } else { - ConsumeElement(reader); + Utilities::ConsumeCurrentElement(&reader); } break; @@ -170,20 +171,6 @@ Song SomaFMService::Stream::ToSong() const { return ret; } -void SomaFMService::ConsumeElement(QXmlStreamReader& reader) { - int level = 1; - while (!reader.atEnd()) { - switch (reader.readNext()) { - case QXmlStreamReader::StartElement: level++; break; - case QXmlStreamReader::EndElement: level--; break; - default: break; - } - - if (level == 0) - return; - } -} - void SomaFMService::Homepage() { QDesktopServices::openUrl(QUrl(kHomepage)); } diff --git a/src/internet/somafmservice.h b/src/internet/somafmservice.h index e24b9aacf..074a7c724 100644 --- a/src/internet/somafmservice.h +++ b/src/internet/somafmservice.h @@ -81,7 +81,6 @@ private slots: private: void ReadChannel(QXmlStreamReader& reader, StreamList* ret); - void ConsumeElement(QXmlStreamReader& reader); void PopulateStreams(); private: diff --git a/src/musicbrainz/musicbrainzclient.cpp b/src/musicbrainz/musicbrainzclient.cpp index e90879afc..054175d15 100644 --- a/src/musicbrainz/musicbrainzclient.cpp +++ b/src/musicbrainz/musicbrainzclient.cpp @@ -18,14 +18,17 @@ #include "musicbrainzclient.h" #include "core/logging.h" #include "core/network.h" +#include "core/utilities.h" #include #include +#include #include #include const char* MusicBrainzClient::kTrackUrl = "http://musicbrainz.org/ws/2/recording/"; const char* MusicBrainzClient::kDiscUrl = "http://musicbrainz.org/ws/1/release/"; +const char* MusicBrainzClient::kDateRegex = "^[12]\\d{3}"; const int MusicBrainzClient::kDefaultTimeout = 5000; // msec MusicBrainzClient::MusicBrainzClient(QObject* parent) @@ -118,16 +121,18 @@ void MusicBrainzClient::DiscIdRequestFinished() { while (!reader.atEnd()) { QXmlStreamReader::TokenType token = reader.readNext(); if (token == QXmlStreamReader::StartElement && reader.name() == "track") { - Result track = ParseTrack(&reader); - if (!track.title_.isEmpty()) { - ret << track; + ResultList tracks = ParseTrack(&reader); + foreach (const Result& track, tracks) { + if (!track.title_.isEmpty()) { + ret << track; + } } } else if (token == QXmlStreamReader::EndElement && reader.name() == "track-list") { break; } } - emit Finished(artist, album, ret); + emit Finished(artist, album, UniqueResults(ret)); } @@ -151,18 +156,21 @@ void MusicBrainzClient::RequestFinished() { QXmlStreamReader reader(reply); while (!reader.atEnd()) { if (reader.readNext() == QXmlStreamReader::StartElement && reader.name() == "recording") { - Result track = ParseTrack(&reader); - if (!track.title_.isEmpty()) { - ret << track; + ResultList tracks = ParseTrack(&reader); + foreach (const Result& track, tracks) { + if (!track.title_.isEmpty()) { + ret << track; + } } } } - emit Finished(id, ret); + emit Finished(id, UniqueResults(ret)); } -MusicBrainzClient::Result MusicBrainzClient::ParseTrack(QXmlStreamReader* reader) { - Result ret; +MusicBrainzClient::ResultList MusicBrainzClient::ParseTrack(QXmlStreamReader* reader) { + Result result; + QList releases; while (!reader->atEnd()) { QXmlStreamReader::TokenType type = reader->readNext(); @@ -171,13 +179,13 @@ MusicBrainzClient::Result MusicBrainzClient::ParseTrack(QXmlStreamReader* reader QStringRef name = reader->name(); if (name == "title") { - ret.title_ = reader->readElementText(); + result.title_ = reader->readElementText(); } else if (name == "length") { - ret.duration_msec_ = reader->readElementText().toInt(); + result.duration_msec_ = reader->readElementText().toInt(); } else if (name == "artist") { - ParseArtist(reader, &ret.artist_); + ParseArtist(reader, &result.artist_); } else if (name == "release") { - ParseAlbum(reader, &ret.album_, &ret.track_); + releases << ParseRelease(reader); } } @@ -186,6 +194,10 @@ MusicBrainzClient::Result MusicBrainzClient::ParseTrack(QXmlStreamReader* reader } } + ResultList ret; + foreach (const Release& release, releases) { + ret << release.CopyAndMergeInto(result); + } return ret; } @@ -203,21 +215,37 @@ void MusicBrainzClient::ParseArtist(QXmlStreamReader* reader, QString* artist) { } } -void MusicBrainzClient::ParseAlbum(QXmlStreamReader* reader, QString* album, int* track) { +MusicBrainzClient::Release MusicBrainzClient::ParseRelease(QXmlStreamReader* reader) { + Release ret; + while (!reader->atEnd()) { QXmlStreamReader::TokenType type = reader->readNext(); if (type == QXmlStreamReader::StartElement) { QStringRef name = reader->name(); if (name == "title") { - *album = reader->readElementText(); + ret.album_ = reader->readElementText(); + } else if (name == "date") { + QRegExp regex(kDateRegex); + if (regex.indexIn(reader->readElementText()) == 0) { + ret.year_ = regex.cap(0).toInt(); + } } else if (name == "track-list") { - *track = reader->attributes().value("offset").toString().toInt() + 1; + ret.track_ = reader->attributes().value("offset").toString().toInt() + 1; + Utilities::ConsumeCurrentElement(reader); } } if (type == QXmlStreamReader::EndElement && reader->name() == "release") { - return; + break; } } + + return ret; +} + +MusicBrainzClient::ResultList MusicBrainzClient::UniqueResults(const ResultList& results) { + ResultList ret = QSet::fromList(results).toList(); + qSort(ret); + return ret; } diff --git a/src/musicbrainz/musicbrainzclient.h b/src/musicbrainz/musicbrainzclient.h index 21c59bfa4..b3ba6ac1b 100644 --- a/src/musicbrainz/musicbrainzclient.h +++ b/src/musicbrainz/musicbrainzclient.h @@ -18,6 +18,7 @@ #ifndef MUSICBRAINZCLIENT_H #define MUSICBRAINZCLIENT_H +#include #include #include #include @@ -40,16 +41,41 @@ public: MusicBrainzClient(QObject* parent = 0); struct Result { - Result() : duration_msec_(0), track_(0) {} + Result() : duration_msec_(0), track_(0), year_(-1) {} + + bool operator <(const Result& other) const { + #define cmp(field) \ + if (field < other.field) return true; \ + if (field > other.field) return false; + + cmp(track_); + cmp(year_); + cmp(title_); + cmp(artist_); + return false; + + #undef cmp + } + + bool operator ==(const Result& other) const { + return title_ == other.title_ && + artist_ == other.artist_ && + album_ == other.album_ && + duration_msec_ == other.duration_msec_ && + track_ == other.track_ && + year_ == other.year_; + } QString title_; QString artist_; QString album_; int duration_msec_; int track_; + int year_; }; typedef QList ResultList; + // Starts a request and returns immediately. Finished() will be emitted // later with the same ID. void Start(int id, const QString& mbid); @@ -75,13 +101,31 @@ private slots: void DiscIdRequestFinished(); private: - static Result ParseTrack(QXmlStreamReader* reader); + struct Release { + Release() : track_(0), year_(0) {} + + Result CopyAndMergeInto(const Result& orig) const { + Result ret(orig); + ret.album_ = album_; + ret.track_ = track_; + ret.year_ = year_; + return ret; + } + + QString album_; + int track_; + int year_; + }; + + static ResultList ParseTrack(QXmlStreamReader* reader); static void ParseArtist(QXmlStreamReader* reader, QString* artist); - static void ParseAlbum(QXmlStreamReader* reader, QString* album, int* track); + static Release ParseRelease(QXmlStreamReader* reader); + static ResultList UniqueResults(const ResultList& results); private: static const char* kTrackUrl; static const char* kDiscUrl; + static const char* kDateRegex; static const int kDefaultTimeout; QNetworkAccessManager* network_; @@ -89,4 +133,13 @@ private: QMap requests_; }; +inline uint qHash(const MusicBrainzClient::Result& result) { + return qHash(result.album_) ^ + qHash(result.artist_) ^ + result.duration_msec_ ^ + qHash(result.title_) ^ + result.track_ ^ + result.year_; +} + #endif // MUSICBRAINZCLIENT_H diff --git a/src/musicbrainz/tagfetcher.cpp b/src/musicbrainz/tagfetcher.cpp index 8d3a3506a..983665889 100644 --- a/src/musicbrainz/tagfetcher.cpp +++ b/src/musicbrainz/tagfetcher.cpp @@ -116,6 +116,7 @@ void TagFetcher::TagsFetched(int index, const MusicBrainzClient::ResultList& res song.Init(result.title_, result.artist_, result.album_, result.duration_msec_ * kNsecPerMsec); song.set_track(result.track_); + song.set_year(result.year_); songs_guessed << song; } diff --git a/src/playlistparsers/xmlparser.cpp b/src/playlistparsers/xmlparser.cpp index 48b08f95e..9b5515e08 100644 --- a/src/playlistparsers/xmlparser.cpp +++ b/src/playlistparsers/xmlparser.cpp @@ -43,20 +43,3 @@ bool XMLParser::ParseUntilElement(QXmlStreamReader* reader, const QString& name) } return false; } - -void XMLParser::IgnoreElement(QXmlStreamReader* reader) const { - int level = 1; - while (level != 0 && !reader->atEnd()) { - QXmlStreamReader::TokenType type = reader->readNext(); - switch (type) { - case QXmlStreamReader::StartElement: - ++level; - break; - case QXmlStreamReader::EndElement: - --level; - break; - default: - break; - } - } -} diff --git a/src/playlistparsers/xmlparser.h b/src/playlistparsers/xmlparser.h index 15fe8d5b1..f9137442d 100644 --- a/src/playlistparsers/xmlparser.h +++ b/src/playlistparsers/xmlparser.h @@ -33,7 +33,6 @@ class XMLParser : public ParserBase { XMLParser(LibraryBackendInterface* library, QObject* parent); bool ParseUntilElement(QXmlStreamReader* reader, const QString& element) const; - void IgnoreElement(QXmlStreamReader* reader) const; class StreamElement : public boost::noncopyable { public: diff --git a/src/ui/trackselectiondialog.cpp b/src/ui/trackselectiondialog.cpp index af08f807e..53c34a7f3 100644 --- a/src/ui/trackselectiondialog.cpp +++ b/src/ui/trackselectiondialog.cpp @@ -60,9 +60,10 @@ TrackSelectionDialog::TrackSelectionDialog(QWidget *parent) // Resize columns ui_->results->setColumnWidth(0, 50); // Track column - ui_->results->setColumnWidth(1, 175); // Title column - ui_->results->setColumnWidth(2, 175); // Artist column - ui_->results->setColumnWidth(3, 175); // Album column + ui_->results->setColumnWidth(1, 50); // Year column + ui_->results->setColumnWidth(2, 160); // Title column + ui_->results->setColumnWidth(3, 160); // Artist column + ui_->results->setColumnWidth(4, 160); // Album column } TrackSelectionDialog::~TrackSelectionDialog() { @@ -198,8 +199,9 @@ void TrackSelectionDialog::AddDivider(const QString& text, QTreeWidget* parent) void TrackSelectionDialog::AddSong(const Song& song, int result_index, QTreeWidget* parent) const { QStringList values; - values << ((song.track() > 0) ? QString::number(song.track()) : QString()); - values << song.title() << song.artist() << song.album(); + values << ((song.track() > 0) ? QString::number(song.track()) : QString()) + << ((song.year() > 0) ? QString::number(song.year()) : QString()) + << song.title() << song.artist() << song.album(); QTreeWidgetItem* item = new QTreeWidgetItem(parent, values); item->setData(0, Qt::UserRole, result_index); diff --git a/src/ui/trackselectiondialog.ui b/src/ui/trackselectiondialog.ui index 89e19d276..77b940101 100644 --- a/src/ui/trackselectiondialog.ui +++ b/src/ui/trackselectiondialog.ui @@ -69,7 +69,7 @@ - + @@ -191,6 +191,11 @@ Track + + + Year + + Title @@ -216,7 +221,7 @@ - + From d5fcc1a24e93055a7def8600914afcbefe008239 Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sun, 8 Jan 2012 12:55:06 +0000 Subject: [PATCH 34/40] Fix a crash on startup after disabling watching the library for changes. Fixes issue 2585 (cherry picked from commit 2e49e89e7b5c5a0ebaa352e429f3e573a1fa778f) --- src/library/librarywatcher.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/library/librarywatcher.cpp b/src/library/librarywatcher.cpp index 41afe69be..a5f5ebf87 100644 --- a/src/library/librarywatcher.cpp +++ b/src/library/librarywatcher.cpp @@ -695,7 +695,9 @@ void LibraryWatcher::ReloadSettings() { } if (!monitor_ && was_monitoring_before) { - fs_watcher_->Clear(); + if (fs_watcher_) { + fs_watcher_->Clear(); + } } else if (monitor_ && !was_monitoring_before) { // Add all directories to all QFileSystemWatchers again foreach (const DirData& data, watched_dirs_.values()) { From fd1c133e249929e425d771c9ee15c39dc41bc9ce Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sun, 8 Jan 2012 17:46:50 +0000 Subject: [PATCH 35/40] Display any SSL or HTTP errors that occur when creating a grooveshark session (cherry picked from commit ff92815ef071abcbddf0bc7c60ffb471716d9465) --- src/internet/groovesharkservice.cpp | 21 +++++++++++++++++++++ src/internet/groovesharkservice.h | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/src/internet/groovesharkservice.cpp b/src/internet/groovesharkservice.cpp index 5c9fd3fcd..87b6ca948 100644 --- a/src/internet/groovesharkservice.cpp +++ b/src/internet/groovesharkservice.cpp @@ -366,6 +366,13 @@ void GroovesharkService::SessionCreated() { reply->deleteLater(); + if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) { + emit StreamError("Failed to create Grooveshark session: " + + reply->errorString()); + emit LoginFinished(false); + return; + } + QVariantMap result = ExtractResult(reply); if (!result["success"].toBool()) { qLog(Error) << "Grooveshark returned an error during session creation"; @@ -1377,9 +1384,23 @@ QNetworkReply* GroovesharkService::CreateRequest(const QString& method_name, QLi QNetworkRequest req(url); QNetworkReply *reply = network_->post(req, post_params); + if (use_https) { + connect(reply, SIGNAL(sslErrors(QList)), + SLOT(RequestSslErrors(QList))); + } + return reply; } +void GroovesharkService::RequestSslErrors(const QList& errors) { + QNetworkReply* reply = qobject_cast(sender()); + + foreach (const QSslError& error, errors) { + emit StreamError("SSL error occurred in Grooveshark request for " + + reply->url().toString() + ": " + error.errorString()); + } +} + bool GroovesharkService::WaitForReply(QNetworkReply* reply) { QEventLoop event_loop; QTimer timeout_timer; diff --git a/src/internet/groovesharkservice.h b/src/internet/groovesharkservice.h index 384744d27..8dbb97aa3 100644 --- a/src/internet/groovesharkservice.h +++ b/src/internet/groovesharkservice.h @@ -21,6 +21,8 @@ #include "internetmodel.h" #include "internetservice.h" +#include + class GroovesharkUrlHandler; class NetworkAccessManager; class Playlist; @@ -174,6 +176,8 @@ class GroovesharkService : public InternetService { void StreamMarked(); void SongMarkedAsComplete(); + void RequestSslErrors(const QList& errors); + void Homepage(); // Refresh all Grooveshark's items, and re-fill them void RefreshItems(); From ada7adcb2f6cc9ef7a295c4ce27252d515c4e191 Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sun, 8 Jan 2012 18:37:46 +0000 Subject: [PATCH 36/40] Create the FilesystemWatcherInterface directly in the LibraryWatcher, fixing a crash when trying to add a new device. (cherry picked from commit d4b4606068b1e73db1aa7ed7227457e220377c4b) --- src/library/library.cpp | 2 -- src/library/librarywatcher.cpp | 6 ++---- src/library/librarywatcher.h | 1 - 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/library/library.cpp b/src/library/library.cpp index 1f8d14322..45733f1d5 100644 --- a/src/library/library.cpp +++ b/src/library/library.cpp @@ -20,7 +20,6 @@ #include "librarymodel.h" #include "librarybackend.h" #include "core/database.h" -#include "core/filesystemwatcherinterface.h" #include "smartplaylists/generator.h" #include "smartplaylists/querygenerator.h" #include "smartplaylists/search.h" @@ -121,7 +120,6 @@ void Library::WatcherInitialised() { watcher->set_backend(backend_); watcher->set_task_manager(task_manager_); - watcher->set_filesystem_watcher(FileSystemWatcherInterface::Create()); connect(backend_, SIGNAL(DirectoryDiscovered(Directory,SubdirectoryList)), watcher, SLOT(AddDirectory(Directory,SubdirectoryList))); diff --git a/src/library/librarywatcher.cpp b/src/library/librarywatcher.cpp index a5f5ebf87..e373868dd 100644 --- a/src/library/librarywatcher.cpp +++ b/src/library/librarywatcher.cpp @@ -49,7 +49,7 @@ LibraryWatcher::LibraryWatcher(QObject* parent) : QObject(parent), backend_(NULL), task_manager_(NULL), - fs_watcher_(NULL), + fs_watcher_(FileSystemWatcherInterface::Create(this)), stop_requested_(false), scan_on_startup_(true), monitor_(true), @@ -695,9 +695,7 @@ void LibraryWatcher::ReloadSettings() { } if (!monitor_ && was_monitoring_before) { - if (fs_watcher_) { - fs_watcher_->Clear(); - } + fs_watcher_->Clear(); } else if (monitor_ && !was_monitoring_before) { // Add all directories to all QFileSystemWatchers again foreach (const DirData& data, watched_dirs_.values()) { diff --git a/src/library/librarywatcher.h b/src/library/librarywatcher.h index 72b69ca16..5fe943ef1 100644 --- a/src/library/librarywatcher.h +++ b/src/library/librarywatcher.h @@ -44,7 +44,6 @@ class LibraryWatcher : public QObject { void set_backend(LibraryBackend* backend) { backend_ = backend; } void set_task_manager(TaskManager* task_manager) { task_manager_ = task_manager; } - void set_filesystem_watcher(FileSystemWatcherInterface* watcher) { fs_watcher_ = watcher; } void set_device_name(const QString& device_name) { device_name_ = device_name; } void IncrementalScanAsync(); From 21441acc947beaabba02ae1db3ea3924c37cfb03 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Mon, 9 Jan 2012 15:30:59 +0100 Subject: [PATCH 37/40] * Add check that chromaprinter is only used from a non-UI thread. * Update copyright date (cherry picked from commit 0c5f422eb8c86291d5fb5693ece033f7c24b3fed) --- src/musicbrainz/chromaprinter.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/musicbrainz/chromaprinter.cpp b/src/musicbrainz/chromaprinter.cpp index 25e56e189..d0adbcc09 100644 --- a/src/musicbrainz/chromaprinter.cpp +++ b/src/musicbrainz/chromaprinter.cpp @@ -1,5 +1,5 @@ /* This file is part of Clementine. - Copyright 2010, David Sansome + Copyright 2012, David Sansome Clementine is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,8 +17,10 @@ #include "chromaprinter.h" +#include #include #include +#include #include #include @@ -32,9 +34,7 @@ Chromaprinter::Chromaprinter(const QString& filename) : filename_(filename), event_loop_(NULL), convert_element_(NULL), - finishing_(false) -{ - buffer_.open(QIODevice::WriteOnly); + finishing_(false) { } Chromaprinter::~Chromaprinter() { @@ -57,6 +57,10 @@ GstElement* Chromaprinter::CreateElement(const QString &factory_name, } QString Chromaprinter::CreateFingerprint() { + Q_ASSERT(QThread::currentThread() != qApp->thread()); + + buffer_.open(QIODevice::WriteOnly); + GMainContext* context = g_main_context_new(); g_main_context_push_thread_default(context); event_loop_ = g_main_loop_new(context, FALSE); From 118985996f7e8627df259895b58aacaa401c73e7 Mon Sep 17 00:00:00 2001 From: David Sansome Date: Mon, 9 Jan 2012 22:53:17 +0000 Subject: [PATCH 38/40] Add ValiCert's root CA to QSslSocket's list to fix an "invalid username/password" error when connecting to Grooveshark on a Windows machine that didn't have all the root CAs installed. Fixes issue 2532 (cherry picked from commit 6ab38e0093b017a4732f6e236e3ec3d303fe3856) --- data/data.qrc | 1 + data/grooveshark-valicert-ca.pem | 19 +++++++++++++++++++ src/main.cpp | 10 ++++++++++ 3 files changed, 30 insertions(+) create mode 100644 data/grooveshark-valicert-ca.pem diff --git a/data/data.qrc b/data/data.qrc index f947641bf..1fc89205b 100644 --- a/data/data.qrc +++ b/data/data.qrc @@ -336,5 +336,6 @@ icons/32x32/search.png schema/schema-35.sql schema/schema-36.sql + grooveshark-valicert-ca.pem diff --git a/data/grooveshark-valicert-ca.pem b/data/grooveshark-valicert-ca.pem new file mode 100644 index 000000000..0c3389594 --- /dev/null +++ b/data/grooveshark-valicert-ca.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz +BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y +aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG +9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy +NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y +azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw +Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl +cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY +dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 +WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS +v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v +UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu +IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC +W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd +-----END CERTIFICATE----- + diff --git a/src/main.cpp b/src/main.cpp index 527ec0264..26a867965 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -65,6 +65,7 @@ #include #include #include +#include #include #include #include @@ -340,6 +341,15 @@ int main(int argc, char *argv[]) { Q_INIT_RESOURCE(data); Q_INIT_RESOURCE(translations); + // Grooveshark uses GoDaddy to sign its SSL certificates, which are in turn + // signed by a ValiCert CA. This CA certificate isn't installed by default + // in Windows, it's only added by windows update, or manually browsing to a + // website with a certificate signed by ValiCert. Here we explicitly add + // that CA to the default list used by QSslSocket, so it always works in + // Clementine. + QSslSocket::addDefaultCaCertificates( + QSslCertificate::fromPath(":/grooveshark-valicert-ca.pem", QSsl::Pem)); + // Has the user forced a different language? QString language = options.language(); if (language.isEmpty()) { From 8e3ce5130420acd9af8806b674073315efe61654 Mon Sep 17 00:00:00 2001 From: David Sansome Date: Wed, 11 Jan 2012 21:26:09 +0000 Subject: [PATCH 39/40] Bump version to 1.0.1 --- cmake/Version.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Version.cmake b/cmake/Version.cmake index a64bfc1ad..ae45c5e7a 100644 --- a/cmake/Version.cmake +++ b/cmake/Version.cmake @@ -3,7 +3,7 @@ # Version numbers. set(CLEMENTINE_VERSION_MAJOR 1) set(CLEMENTINE_VERSION_MINOR 0) -set(CLEMENTINE_VERSION_PATCH 0) +set(CLEMENTINE_VERSION_PATCH 1) #set(CLEMENTINE_VERSION_PRERELEASE rc1) # This should be set to OFF in a release branch From dfc4b4546fb0db6b849c892822bceed666c55a4e Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sun, 22 Jan 2012 11:28:52 +0000 Subject: [PATCH 40/40] Update changelog for 1.0.1 --- Changelog | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Changelog b/Changelog index 3f730ec94..13e2caebb 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,13 @@ +Version 1.0.1: + Bugfixes: + * Use Chromaprinter and Acoustid instead of Echoprint and MusicDNS. + * Make it possible to play songs from connected iPod Touches again. + * (Windows) Fix an SSL issue that would sometimes result in an "Invalid + username or password" error when logging in to Grooveshark. + * (Mac OS X) Use FSEvent-based filesystem watcher to fix a number of crashes + due to running out of file handles when monitoring a large library. + + Version 1.0: Major features: * Add Spotify support.