clam-1.4.0/0000755000000000000000000000000011344231517011127 5ustar rootrootclam-1.4.0/test/0000755000000000000000000000000011344231441012102 5ustar rootrootclam-1.4.0/test/NonPortedTests/0000755000000000000000000000000011344231441015035 5ustar rootrootclam-1.4.0/test/NonPortedTests/TestSpectrumAdder2.cxx0000644000000000000000000001234010037512361021246 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* WARNING WARNING WARNING: This test will only pass if CLAM_DOUBLE is defined */ #include #include //rand() #include "SpectrumAdder2.hxx" #include "SpectrumComp.hxx" #include "OctaveVector.hxx" namespace CLAMTest { // Loads the vectors from a file, if they have not been previously loaded, // and sets the arguments to the loaded values. bool SetTestVectors(Spectrum &s1, Spectrum &s2, Spectrum &s3) { bool remove1=false,remove2=false,remove3=false; static bool loaded=false; static Spectrum orig1,orig2,orig3; if (!loaded) { std::ifstream file("SpectrumAdder2Test.data"); SpecTypeFlags f; f.bMagPhase=false; f.bComplex=true; orig1.SetSize(1024); orig2.SetSize(1024); orig3.SetSize(1024); orig1.SetType(f); orig2.SetType(f); orig3.SetType(f); if (file) { std::cerr << "Loading Input1..." << std::endl; if (!CLAMTest::LoadOctaveComplexVector(file,"Input1",orig1.GetComplexArray())) { std::cerr << "Could not find Input1 vector in input!" << std::endl; return false; } std::cerr << "Loading Input2..." << std::endl; if (!CLAMTest::LoadOctaveComplexVector(file,"Input2",orig2.GetComplexArray())) { std::cerr << "Could not find Audio vector in input!" << std::endl; return false; } std::cerr << "Loading Output..." << std::endl; if (!CLAMTest::LoadOctaveComplexVector(file,"Output",orig3.GetComplexArray())) { std::cerr << "Could not find Audio vector in input!" << std::endl; return false; } file.close(); } else { std::cerr << "Generating Inputs and output..." << std::endl; for (int i = 0; i < 1024; i++) { orig1.GetComplexArray().GetPtr()[i] = Complex(10.0*(TData)rand()/(TData)RAND_MAX, 10.0*(TData)rand()/(TData)RAND_MAX); orig2.GetComplexArray().GetPtr()[i] = Complex(10.0*(TData)rand()/(TData)RAND_MAX, 10.0*(TData)rand()/(TData)RAND_MAX); orig3.GetComplexArray().GetPtr()[i] = orig1.GetComplexArray().GetPtr()[i] + orig2.GetComplexArray().GetPtr()[i]; } } loaded=true; } SpecTypeFlags spec; s1.GetType(spec); if (!spec.bComplex) { spec.bComplex=1; s1.SetType(spec); remove1=true; } s2.GetType(spec); if (!spec.bComplex) { spec.bComplex=1; s2.SetType(spec); remove2=true; } s3.GetType(spec); if (!spec.bComplex) { spec.bComplex=1; s3.SetType(spec); remove3=true; } s1.SetComplexArray(orig1.GetComplexArray()); s2.SetComplexArray(orig2.GetComplexArray()); s3.SetComplexArray(orig3.GetComplexArray()); spec.bMagPhase=spec.bPolar=spec.bMagPhaseBPF=false; s1.SynchronizeTo(spec); s2.SynchronizeTo(spec); s3.SynchronizeTo(spec); if (remove1) { s1.GetType(spec); spec.bComplex=false; s1.SetType(spec); } if (remove2) { s2.GetType(spec); spec.bComplex=false; s2.SetType(spec); } if (remove3) { s3.GetType(spec); spec.bComplex=false; s3.SetType(spec); } return true; } void SetPrototypes(int proto, Spectrum &s) { SpecTypeFlags f; f.bComplex=proto&(1<<(int)SpecTypeFlags::eComplex); f.bPolar=proto&(1<<(int)SpecTypeFlags::ePolar); f.bMagPhase=proto&(1<<(int)SpecTypeFlags::eMagPhase); f.bMagPhaseBPF=proto&(1<<(int)SpecTypeFlags::eMagPhaseBPF); s.SetType(f); } bool TestAdder(SpectrumAdder2 &adder) { #ifdef CLAM_DOUBLE TData max_err = 0.000001; #else TData max_err = 0.15f; #endif Spectrum in1,in2,out,out_good; int proto1,proto2,proto3; adder.Start(); in1.SetSize(1024); in2.SetSize(1024); out.SetSize(1024); out_good.SetSize(1024); for (proto1=1; proto1<16; proto1++) for (proto2=1; proto2<16; proto2++) for (proto3=1; proto3<16; proto3++) { if (proto3 & 8) { // Skip BPF outputs for now... std::cerr << "skipped "; continue; } SetPrototypes(proto1,in1); SetPrototypes(proto2,in2); SetPrototypes(proto3,out); SetTestVectors(in1,in2,out_good); adder.SetPrototypes(in1,in2,out); adder.Do(in1,in2,out); TData diff = CLAMTest::TestUtils::MaxDiff(out,out_good); std::cerr << diff << ' '; if (diff > max_err) return false; std::cerr.flush(); } return true; } } int main() { try { CLAM::SpectrumAdder2 adder; bool res = CLAMTest::TestAdder(adder); if (res) std::cerr << std::endl << "Passed." << std::endl; else std::cerr << std::endl << "Failed." << std::endl; return !res; } catch (CLAM::Err e) { e.Print(); } } clam-1.4.0/test/NonPortedTests/SegmentTest.cxx0000644000000000000000000001125211076377340020037 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "Segmentator.hxx" #include "MonoAudioFileReader.hxx" #include #include "CLAM_Math.hxx" #include "Segment.hxx" #include "Frame.hxx" #include #include "XMLTestHelper.hxx" using namespace CLAM; #define NCHILDRENPERSEGMENT 30 void Segmentate(Segment& in) { int i; TData beginTime=in.GetBeginTime(); TData duration=in.GetEndTime()-in.GetBeginTime(); TData step=duration/NCHILDRENPERSEGMENT ; for(i=0;i>fileName; } else fileName = argv[1]; //The File I/O PO MonoAudioFileReaderConfig infilecfg; infilecfg.SetSourceFile(fileName); MonoAudioFileReader myAudioFileIn(infilecfg); ///////////////////////////////////////////////////////////////////////////// // Initialization of the processing data objects : TSize fileSize=myAudioFileIn.GetHeader().GetSamples(); Audio readAudio; // read Audio object readAudio.SetSize(fileSize); TData samplingRate=readAudio.GetSampleRate(); //Read Audio File myAudioFileIn.Start(); myAudioFileIn.Do(readAudio); // Segment that will actually hold data Segment mySegment; mySegment.SetHoldsData(true); float duration=fileSize/samplingRate; std::cout << "The audio file has a total of" << duration << std::endl; mySegment.SetEndTime(duration); mySegment.SetAudio(readAudio); //Segmentate std::cout << "Starting first level segmentation" << std::endl; Segmentate(mySegment); //Now I will try to segmentate the every note into Attack/Steady_State/Release int z; int i; std::cout << "Starting second level segmentation" << std::endl; for(i=0;i #include using std::cout; using namespace CLAM; namespace CLAMTest{ class Log { public: TData operator() (const TData arg) { return log(arg); } }; class Double { public: TData operator() (const TData arg) { return arg*2; } }; }; //namespace int TestTabFunction() { TabFunct f(100, TData(2.01), 100); TabFunct g(3, 0, 100); TData maxerror=0; for (TData x=TData(2.01); x<=100; x+=5) { TData newerror = std::abs(f.Log::operator() (x) - f(x)); maxerror = maxerror < newerror? newerror : maxerror; cout << f(x) << " (" << f.Log::operator() (x) <<") "; } cout << "\nLog Max Error = "< 0.001) { cout << "Error too high\n"; return -1; } maxerror=0; for (TData x=TData(0.01); x<=100; x+=5) { TData newerror = std::abs(g.Double::operator() (x) - g(x)); maxerror = maxerror < newerror? newerror : maxerror; cout << g(x) << " (" << g.Double::operator() (x) <<") "; } cout << "\nDouble Max Error = "< 0.001) { cout << "Error too high\n"; return -1; } return 0; } int main(void) { return TestTabFunction(); } clam-1.4.0/test/NonPortedTests/TestWaveGenerator.cxx0000644000000000000000000001267410610720021021174 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "TestUtils.hxx" #include "Err.hxx" // Here you should include the class you want to test! #include "WaveGenerator.hxx" // And you may want to provide some feedback. #include namespace CLAMTest { class WaveGeneratorTest { CLAM::WaveGenerator *mpObject1; CLAM::WaveGenerator *mpObject2; int mDataLength; int mPos; int mSize; TData mAmpl1; TTime mFrec1; TTime mPhase1; TTime mSampleRate1; TData mAmpl2; TTime mFrec2; TTime mPhase2; TTime mSampleRate2; int mData1Length; int mData2Length; TData mThreshold; TData Sine1(int pos); TData Sine2(int pos); bool CheckSine1Data(Audio &data1, int pos); bool CheckSine2Data(Audio &data2, int pos); bool TestSine(); // Basic Test methods. You should make them bigger, and maybe // add some more. // You can notify a test failure either by throwing an // exception inside them or by making them return a false // value. In the first case no more checks will be made. In // the second case tests will continue, but at the end a test // failure will be reported. bool TestConstruction(); bool TestConfiguration(); bool TestExecution(); bool TestDestruction(); public: WaveGeneratorTest(); bool Do(); }; WaveGeneratorTest::WaveGeneratorTest() : mpObject1(0), mpObject2(0), mDataLength(10000), mPos(0), mSize(222), mAmpl1(2.0), mFrec1(1000.0), mPhase1(0.555), mSampleRate1(8000), mAmpl2(3.0), mFrec2(200.0), mPhase2(1.333), mSampleRate2(48000), mThreshold(0.025) { } bool WaveGeneratorTest::TestConstruction() { CLAM::WaveGeneratorConfig cfg; // You should add more constructions here, // using different configuration parameters, or // other constructors the class may provide. mpObject1 = new CLAM::WaveGenerator(); mpObject2 = new CLAM::WaveGenerator(cfg); return true; } bool WaveGeneratorTest::TestConfiguration() { CLAM::WaveGeneratorConfig cfg1,cfg2; cfg1.SetFrequency(mFrec1); cfg1.SetAmplitude(mAmpl1); cfg1.SetPhase(mPhase1); cfg1.SetSampleRate(mSampleRate1); cfg2.SetFrequency(mFrec2); cfg2.SetAmplitude(mAmpl2); cfg2.SetPhase(mPhase2); cfg2.SetSampleRate(mSampleRate2); mpObject1->Configure(cfg2); mpObject1->Configure(cfg1); mpObject2->Configure(cfg1); mpObject2->Configure(cfg2); return true; } TData WaveGeneratorTest::Sine1(int pos) { return mAmpl1 * sin(mPhase1 + pos * mFrec1 * 2.0 * M_PI/ mSampleRate1); } TData WaveGeneratorTest::Sine2(int pos) { return mAmpl2 * sin(mPhase2 + pos * mFrec2 * 2.0 * M_PI/ mSampleRate2); } bool WaveGeneratorTest::CheckSine1Data(Audio &data1, int pos) { int i; Array &buff = data1.GetBuffer(); for (i=0; i mThreshold) return false; } return true; } bool WaveGeneratorTest::CheckSine2Data(Audio &data2, int pos) { int i; Array &buff = data2.GetBuffer(); for (i=0; i mThreshold) return false; } return true; } bool WaveGeneratorTest::TestSine() { Audio data1,data2; data1.SetSize(mSize); data2.SetSize(mSize); mpObject1->Start(); mpObject2->Start(); while (mPos < mDataLength + data1.GetSize()) { mpObject1->Do(data1); mpObject2->Do(data2); if (!CheckSine1Data(data1,mPos)) return false; if (!CheckSine2Data(data2,mPos)) return false; mPos += data1.GetSize(); } mpObject1->Stop(); mpObject2->Stop(); return true; } bool WaveGeneratorTest::TestExecution() { bool ok = true; ok &= TestSine(); return ok; } bool WaveGeneratorTest::TestDestruction() { delete mpObject1; delete mpObject2; return true; } bool WaveGeneratorTest::Do() { bool res, ok = true; res = TestConstruction(); CLAM_ASSERT( res, "Construction failed" ); res = TestConfiguration(); CLAM_ASSERT( res, "Configuration failed." ); res = TestExecution(); CLAM_ASSERT( res, "Execution has failed" ); res = TestDestruction(); CLAM_ASSERT( res, "Destruction failed." ); return ok; } } // main() return values: // 0: Test sucessful. // non-zero: Test Failed. int main() { try { CLAMTest::WaveGeneratorTest test; bool result = test.Do(); if (result==false) { std::cerr << "Failed." << std::endl; return 1; } } catch ( CLAM::Err e ) { e.Print(); std::cerr << "Abnormal Program termination" << std::endl; std::cerr << "Failed." << std::endl; return 1; } catch (std::exception &e) { std::cerr << "ERROR: Excepton: " << e.what() << std::endl << "Failed." << std::endl; return 1; } std::cerr << "Passed." << std::endl; return 0; } clam-1.4.0/test/NonPortedTests/ListTest.cxx0000644000000000000000000001625710037512361017350 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "List.hxx" #include #include #include #include #include "Assert.hxx" #include "XMLTestHelper.hxx" #define NITERATIONS 2000 namespace CLAMTest { using namespace CLAM; template bool CorrectSequentialValues(const List& myList) { CLAM_ASSERT(myList.FulfillsInvariant(),"List does not Fulfill Invariant"); if((!myList.IsEmpty())&&(myList.CurrentIndex()!=myList.Current()||myList.First()!=0|| myList.Last()!=myList.Size()-1)) return false; else return true; } } using CLAM::Err; int main() { try{ CLAM::List testList; int testElem; /*Sequential additions*/ if(testList.IsEmpty()) std::cout<<"List is empty, OK!"; else std::cout<<"List is not empty, Error!"; std::cout<<"Sequential Additions\n"; for(int i=0;i>c;*/ /*Sequential Extractions*/ for(int i=0;i=0) std::cout<<"Current Element is "<>c; std::cout<<"Random Value Additions Finished Successfully, starting Random Isertions\n"; std::cout<<"Press enter when ready\n"; std::cin>>c;*/ /*Additions*/ for(int i=0;i=0) std::cout<<"Current Element is "<>c; /*Random Accesses*/ for(int i=0;i=0) std::cout<<"Current Element is "<>c;*/ /* Copy */ List copyList, *copyList2; copyList=testList; CLAM_ASSERT(copyList.FulfillsInvariant(), "List does not fullfil invariant"); copyList2=new List(testList); CLAM_ASSERT(copyList2->FulfillsInvariant(), "List does not fullfil invariant"); delete copyList2; // Storing result to XML document and check if loading matches CLAM_ASSERT(CLAMTest::XMLInputOutputMatches(testList, "ListTest.xml"), "Original resulting list and XML reloaded one don't match"); /*Random Extractions*/ for(int i=0;i<2*NITERATIONS;i++) { current=int((double(rand())/RAND_MAX)*(2*NITERATIONS-i-1)); testList.Extract(testElem,current); std::cout<<"Element in position "<=0) std::cout<<"Current Element is "<>c;*/} else throw Err("List is not empty, ERROR!"); } catch(Err err) { err.Print(); } return 0; } clam-1.4.0/test/NonPortedTests/TestThreading.cxx0000644000000000000000000002776710610720021020341 0ustar rootroot#include "Mutex.hxx" #include "RecursiveMutex.hxx" #include "Condition.hxx" #include "Thread.hxx" #include "xtime.hxx" #include using std::cout; using std::endl; #include #include "Assert.hxx" #include "Err.hxx" template < typename M > void test_lock( M* overload_provider = 0 ) { typedef M MutexType; typedef typename M::ScopedLock LockType; MutexType mutex; CLAM::Condition condition; // Test lock constructors { LockType lock( mutex, false ); CLAM_ASSERT( !lock, "ScopedLock constructor failed" ); } LockType lock( mutex ); CLAM_ASSERT( lock, "ScopedLock constructor failed" ); // Time out test. Since nobody notifies the condition variable // it should time out CLAM::xtime xt; CLAM_ASSERT( CLAM::xtime_get(&xt, CLAM::TIME_UTC) == CLAM::TIME_UTC, " Something went wrong with time initialization" ); xt.nsec += 100000000; // one tenth of a sec CLAM_ASSERT( condition.TimedWait( lock, xt ) == false, "Condition didn't timeout" ); CLAM_ASSERT( lock, "Lock was messed up" ); // Test the lock and unlock lock.Unlock(); CLAM_ASSERT( !lock, "Lock not unlocked!" ); lock.Lock(); CLAM_ASSERT( lock, "Unlocked lock not locked" ); } template void test_trylock( M* overload_provider = 0 ) { typedef M MutexType; typedef typename M::ScopedTryLock TryLockType; MutexType mutex; CLAM::Condition condition; // Lock constructors test { TryLockType lock( mutex ); CLAM_ASSERT( lock, "Constructor failed" ); } { TryLockType lock( mutex, false); CLAM_ASSERT( !lock, "Constructor failed" ); } TryLockType lock( mutex, true ); CLAM_ASSERT( lock, "Constructor failed" ); // Fast timeout CLAM::xtime xt; CLAM_ASSERT( CLAM::xtime_get( &xt, CLAM::TIME_UTC ) == CLAM::TIME_UTC, "Clock test failed" ); xt.nsec += 100000000; // one tenth of a second // This should timeout CLAM_ASSERT( condition.TimedWait( lock ,xt ) == false, "Condition didn't time out" ); CLAM_ASSERT( lock, "Lock was messed" ); // now we try the lock, unlock and trylock lock.Unlock(); CLAM_ASSERT( !lock, "Unlock() did not work" ); lock.Lock(); CLAM_ASSERT( lock, "Lock() did not work" ); lock.Unlock(); CLAM_ASSERT( !lock, "Unlock() did not work" ); CLAM_ASSERT( lock.TryLock(), "Unable to acquire a lock onto a unlocked mutex" ); CLAM_ASSERT( lock, "mutex not locked" ); } template void test_timedlock( M* overload_provider = 0) { typedef M MutexType; typedef typename M::ScopedTimedLock TimedLockType; MutexType mutex; CLAM::Condition condition; // Test the lock's constructors. { // Construct and initialize an xtime for a fast time out. CLAM::xtime xt; CLAM_ASSERT(CLAM::xtime_get(&xt, CLAM::TIME_UTC) == CLAM::TIME_UTC, "Clock Test failed"); xt.nsec += 100000000; // one tenth of a second TimedLockType lock(mutex, xt); CLAM_ASSERT(lock, "Constructor failed"); } { TimedLockType lock(mutex, false); CLAM_ASSERT(!lock, "Constructor failed"); } TimedLockType lock(mutex, true); CLAM_ASSERT(lock, "Constructor failed"); // Construct and initialize an xtime for a fast time out. CLAM::xtime xt; CLAM_ASSERT(CLAM::xtime_get(&xt, CLAM::TIME_UTC) == CLAM::TIME_UTC, "Clock test failed"); xt.nsec += 100000000; // Test the lock and the mutex with condition variables. // No one is going to notify this condition variable. We expect to // time out. CLAM_ASSERT(condition.TimedWait(lock, xt) == false, "Condition did not timeout"); CLAM_ASSERT(lock,"Test failed"); // Test the lock, unlock and timedlock methods. lock.Unlock(); CLAM_ASSERT(!lock, "Unlock() failed"); lock.Lock(); CLAM_ASSERT(lock, "Lock() failed"); lock.Unlock(); CLAM_ASSERT(!lock, "Unlock() failed"); CLAM_ASSERT(CLAM::xtime_get(&xt, CLAM::TIME_UTC) == CLAM::TIME_UTC, "Test failed"); xt.nsec += 100000000; CLAM_ASSERT(lock.TimedLock(xt), "TimedLock() did not work"); } void test_mutex() { typedef CLAM::Mutex mutex; test_lock(); cout << "Mutex test passed...." << endl; } void test_try_mutex() { typedef CLAM::TryMutex mutex; test_lock(); test_trylock(); cout << "TryMutex test passed..." << endl; } void test_timed_mutex() { typedef CLAM::TimedMutex mutex; test_lock(); test_trylock(); test_timedlock(); cout << "TimedMutex test passed..." << endl; } void test_recursive_mutex() { typedef CLAM::RecursiveMutex mutex; test_lock(); mutex m; { mutex::ScopedLock lock1( m ); mutex::ScopedLock lock2( m ); } cout << "RecursiveMutex test passed..." << endl; } void test_recursive_try_mutex() { typedef CLAM::RecursiveTryMutex mutex; test_lock(); test_trylock(); mutex m; { mutex::ScopedLock lock1(m); mutex::ScopedLock lock2(m); } cout << "RecursiveTryMutex test passed..." << endl; } void test_recursive_timed_mutex() { typedef CLAM::RecursiveTimedMutex mutex; test_lock(); test_trylock(); test_timedlock(); mutex m; { mutex::ScopedLock lock1(m); mutex::ScopedLock lock2(m); } cout << "RecursiveTimedMutex test passed..." << endl; } class TestCondition { public: TestCondition() : notified(0), awoken(0) { } virtual void ThreadCode() { CLAM::Mutex::ScopedLock lock( mutex ); CLAM_ASSERT( lock, "Lock did not worked" ); while ( !(notified) ) condition.Wait(lock); CLAM_ASSERT( lock, "Lock was messed" ); awoken++; } public: CLAM::Mutex mutex; CLAM::Condition condition; int notified; int awoken; }; void test_condition_notify_one() { TestCondition test_cond; CLAM::Thread t; t.SetThreadCode( makeMemberFunctor0( test_cond, TestCondition, ThreadCode ) ); t.Start(); { CLAM::Mutex::ScopedLock lock( test_cond.mutex ); CLAM_ASSERT( lock, "Unable to lock the mutex" ); test_cond.notified++; test_cond.condition.NotifyOne(); } t.Stop(); CLAM_ASSERT(test_cond.awoken==1,"Test Condition::NotifyOne failed!" ); cout << "Test Condition::NotifyOne passed!" << endl; } void test_condition_notify_all() { const int nthreads = 5; typedef std::list ThreadGroup; typedef std::list::iterator TGIterator; ThreadGroup threads; TestCondition test_cond; for ( int i = 0; i < nthreads; i++ ) threads.push_back( new CLAM::Thread() ); TGIterator it; for ( it = threads.begin(); it != threads.end(); it++) (*it)->SetThreadCode( makeMemberFunctor0( test_cond, TestCondition, ThreadCode ) ); for ( it = threads.begin(); it != threads.end(); it++ ) (*it)->Start(); { CLAM::Mutex::ScopedLock lock( test_cond.mutex ); CLAM_ASSERT( lock, "Not able to lock: Test Condition::NotifyAll failed" ); test_cond.notified++; test_cond.condition.NotifyAll(); } for ( it = threads.begin(); it != threads.end(); it++ ) (*it)->Stop(); for ( it = threads.begin(); it != threads.end(); it++ ) delete (*it); CLAM_ASSERT( test_cond.awoken == nthreads, "Test Condition::NotifyAll failed" ); cout << "Test Condition::NotifyAll passed" << endl; } struct ConditionPredicate { ConditionPredicate( int& var, int val ) : mVar(var), mVal(val) { } bool operator() () { return mVar == mVal; } int& mVar; int mVal; }; class TestConditionWait : public TestCondition { public: virtual void ThreadCode() { CLAM::Mutex::ScopedLock lock( mutex ); CLAM_ASSERT( lock, "Test Condition Wait failed: not able to lock the mutex" ); // Test wait while ( !notified ) condition.Wait( lock ); CLAM_ASSERT( lock, "Test Condition Wait failed: lock messed up during wait" ); CLAM_ASSERT( notified == 1, "Test Condition Wait failed: guard var messed" ); awoken++; condition.NotifyOne(); // Test predicate wait condition.Wait( lock, ConditionPredicate( notified, 2 ) ); CLAM_ASSERT( lock, "Test Condition Wait failed: lock messed during wait" ); CLAM_ASSERT( notified == 2, "Test Condition Wait failed: Guard variable failed" ); awoken++; condition.NotifyOne(); // Test timed_wait. CLAM::xtime xt; CLAM_ASSERT( CLAM::xtime_get(&xt, CLAM::TIME_UTC) == CLAM::TIME_UTC, "Clock mismatch!" ); xt.nsec += 100000000; // one tenth of a second while (notified != 3) condition.TimedWait(lock, xt); CLAM_ASSERT(lock, "Test Condition Wait failed: lock messed during wait" ); CLAM_ASSERT(notified == 3, "Test Condition Wait failed: Guard variable messed"); awoken++; condition.NotifyOne(); // Test predicate timed_wait. CLAM_ASSERT(CLAM::xtime_get(&xt, CLAM::TIME_UTC) == CLAM::TIME_UTC, "Clock mismatch!" ); xt.sec += 2; CLAM_ASSERT( condition.TimedWait(lock, xt, ConditionPredicate(notified, 4)), "Test Condition Wait failed: TimedOut!"); CLAM_ASSERT(lock, "Lock messed during wait"); CLAM_ASSERT(notified == 4, "Test Condition Wait failed: Guard variable messed"); awoken++; } }; void test_condition_waits() { TestConditionWait test_cond; TestCondition* pBase; CLAM::Thread t; pBase = static_cast( &test_cond ); // upcast t.SetThreadCode( makeMemberFunctor0( *pBase, TestCondition, ThreadCode ) ); t.Start(); CLAM::xtime xt; { CLAM::Mutex::ScopedLock lock( test_cond.mutex ); CLAM_ASSERT( lock, "Test condition wait failed: mutex not locked" ); t.Sleep( 1000 ); test_cond.notified++; test_cond.condition.NotifyOne(); while (test_cond.awoken != 1) test_cond.condition.Wait(lock); CLAM_ASSERT(test_cond.awoken == 1, "Test failed" ); CLAM_ASSERT(CLAM::xtime_get(&xt, CLAM::TIME_UTC) == CLAM::TIME_UTC, "test condition waits failed"); t.Sleep( 1000 ); test_cond.notified++; test_cond.condition.NotifyOne(); while (test_cond.awoken != 2) test_cond.condition.Wait(lock); CLAM_ASSERT(test_cond.awoken == 2, "test condition waits failed"); CLAM_ASSERT(CLAM::xtime_get(&xt, CLAM::TIME_UTC) == CLAM::TIME_UTC, "test condition waits failed"); t.Sleep( 1000 ); test_cond.notified++; test_cond.condition.NotifyOne(); while (test_cond.awoken != 3) test_cond.condition.Wait(lock); CLAM_ASSERT(test_cond.awoken == 3, "test condition waits failed"); } CLAM_ASSERT(CLAM::xtime_get(&xt, CLAM::TIME_UTC) == CLAM::TIME_UTC, "test condition waits failed"); t.Sleep( 1000 ); test_cond.notified++; test_cond.condition.NotifyOne(); CLAM_ASSERT(CLAM::xtime_get(&xt, CLAM::TIME_UTC) == CLAM::TIME_UTC, "test condition waits failed"); t.Sleep(1000); t.Stop(); CLAM_ASSERT(test_cond.awoken == 4, "test condition waits failed"); cout << "Test condition waits passed" << endl; } void test_condition() { cout << "Testing Condition::NotifyOne() " << std::endl; test_condition_notify_one(); cout << "Testing Condition::NotifyAll() " << std::endl; test_condition_notify_all(); cout << "Testing Condition:: waits" << std::endl; test_condition_waits(); } class Sleepy { public: void ThreadCode() { double b = 10.5; double c = 0.71; for ( int i = 0; i < 1000000L; i++) { double a = b / c; } } }; void test_sleep_and_wake() { Sleepy sl; CLAM::Thread t; t.SetThreadCode( makeMemberFunctor0( sl, Sleepy, ThreadCode ) ); t.Start(); t.Sleep(1000); cout << "*"; for ( int i = 0; i < 10; i++ ) cout << "+"; cout << endl; t.WakeUp(); t.Stop(); cout << "Test sleep and wake passed!" << endl; } int main( int argc, char** argv ) { try { cout << "Testing Mutex class" << endl; test_mutex(); cout << "Testing TryMutex class" << endl; test_try_mutex(); cout << "Testing TimedMutex class" << endl; test_timed_mutex(); cout << "Testing Recursive Mutex class" << endl; test_recursive_mutex(); cout << "Testing Recursive TryMutex class" << endl; test_recursive_try_mutex(); cout << "Testing Recursive TimedMutex class" << endl; test_recursive_timed_mutex(); cout << "Testing Sleep and Wakeup" << endl; // test_sleep_and_wake(); cout << "Testing Condition class" << endl; test_condition(); cout << "All tests passed. Congratulations!" << endl; } catch( CLAM::Err& e ) { e.Print(); std::cerr << "Abnormal program termination" << std::endl; } return 0; } clam-1.4.0/test/NonPortedTests/TestAssert.sh0000644000000000000000000000046310037512361017476 0ustar rootroot#!/bin/bash for cocksure in "" -DCLAM_DISABLE_CHECKS; do for debug in "" -DDEBUG; do for userelease in "" -DCLAM_USE_RELEASE_ASSERTS; do echo "-------------- Active flags: $debug $userelease $cocksure" g++ -g $debug $userelease $cocksure CLAMAssert.cxx TestAssert.cxx ./a.out done done done clam-1.4.0/test/NonPortedTests/TestControlMapper.cxx0000644000000000000000000000144010610720021021175 0ustar rootroot#include "ControlMapper.hxx" #include "Err.hxx" #include using namespace CLAM; int main(void) { try { ControlMapperConfig mapperCfg; mapperCfg.SetMapping("linear"); TData ptr[]={0.0, 127.0, 0.0, 1.0}; mapperCfg.SetArguments(DataArray(ptr,4)); ControlMapper mapper(mapperCfg); } catch ( Err& e ) { std::cout << "Test Failed." << std::endl; std::cout << "CLAM recognized error: " << std::endl; e.Print(); return -1; } catch ( std::exception& e ) { std::cout << "Test Failed." << std::endl; std::cout << "STL recognized error: " << std::endl; e.what(); return -1; } catch( ... ) { std::cout << "Test Failed." << std::endl; std::cout << "Unknown error" << std::endl; return -1; } std::cout << "Test Passed." << std::endl; return 0; } clam-1.4.0/test/NonPortedTests/TestSignalv1.cxx0000644000000000000000000001032711076377340020123 0ustar rootroot#include #include "Slotv1.hxx" #include "Signalv1.hxx" #include #include using SigSlot::Slotv1; using SigSlot::Signalv1; namespace CLAMTest { class Signaler { public: void Simulate(); Signalv1& GetNewIntegerSignal(); private: Signalv1 mNewInteger; }; class SlottedBase { public: virtual void PureVirtualReact( int value ) = 0; virtual bool WasCorrectlyNotified() = 0; virtual ~SlottedBase() { } }; class Slotted : public SlottedBase { public: Slotted() : mNotified(0), mPureVirtualNotified(0) { mSignalSlot.Wrap(this, &Slotted::React); mStaticSignalSlot.Wrap(&Slotted::sReact); mPureVirtualSignalSlot.Wrap(this, &Slotted::PureVirtualReact); } static void sReact( int value ); void PureVirtualReact( int value ); void React( int value ); void LinkWith( Signaler& sig ); virtual bool WasCorrectlyNotified(); protected: int mNotified; int mPureVirtualNotified; static int smNotified; Slotv1 mSignalSlot; Slotv1 mStaticSignalSlot; Slotv1 mPureVirtualSignalSlot; }; typedef std::vector tSignalerVector; typedef std::vector::iterator tSignalerIterator; class SlottedMultipleSignals : public Slotted { public: SlottedMultipleSignals() : Slotted(), mNumOfExpectedCalls( 0 ) { } virtual bool WasCorrectlyNotified(); void LinkWith( tSignalerVector& multipleSignals ); private: int mNumOfExpectedCalls; }; } namespace CLAMTest { // Signaler class void Signaler::Simulate() { mNewInteger.Emit( 33 ); } Signalv1& Signaler::GetNewIntegerSignal() { return mNewInteger; } // Slotted class void Slotted::sReact( int value ) { smNotified++; std::cout << "Value received " << value << std::endl; } void Slotted::PureVirtualReact( int value ) { mPureVirtualNotified++; std::cout << "Value received" << value << std::endl; } void Slotted::React( int value ) { mNotified++; std::cout << "Value received " << value << std::endl; } void Slotted::LinkWith( Signaler& sig ) { sig.GetNewIntegerSignal().Connect( mSignalSlot ); sig.GetNewIntegerSignal().Connect( mStaticSignalSlot ); sig.GetNewIntegerSignal().Connect( mPureVirtualSignalSlot ); } bool Slotted::WasCorrectlyNotified() { return (mNotified==1) && (smNotified==1) && (mPureVirtualNotified==1); } int Slotted::smNotified = 0; // SlottedMultipleSignals class bool SlottedMultipleSignals::WasCorrectlyNotified() { return ( mNotified == mNumOfExpectedCalls ) && ( smNotified == mNumOfExpectedCalls ) && ( mPureVirtualNotified == mNumOfExpectedCalls ); } void SlottedMultipleSignals::LinkWith( tSignalerVector& signalers ) { smNotified = 0; tSignalerIterator i = signalers.begin(); tSignalerIterator end = signalers.end(); mNumOfExpectedCalls = signalers.size(); while( i != end ) { i->GetNewIntegerSignal().Connect( mSignalSlot ); i->GetNewIntegerSignal().Connect( mStaticSignalSlot ); i->GetNewIntegerSignal().Connect( mPureVirtualSignalSlot ); i++; } } } namespace CLAMTest { void Check( SlottedBase& s ) { if ( s.WasCorrectlyNotified() ) { std::cout << "Test Passed" << std::endl; } else { std::cerr << "Test Failed" << std::endl; std::cerr << "Receiver was not notified" << std::endl; std::abort(); } } void BasicTest() { Signaler emitter; Slotted receiver; receiver.LinkWith( emitter ); emitter.Simulate(); Check( receiver ); std::cout << "Basic Functionality test passed" << std::endl; } void MultipleSignalsConnectedTest() { tSignalerVector emitterVector; int k = 0; int signalCardinal = 10; for ( k = 0; k < signalCardinal; k++ ) { emitterVector.push_back( Signaler() ); } SlottedMultipleSignals receiver; receiver.LinkWith( emitterVector ); for ( k = 0; k < signalCardinal; k++ ) { emitterVector[k].Simulate(); } Check( receiver ); std::cout << "Multiple Signals connected to same slot test passed" << std::endl; } } using namespace CLAMTest; int main( int argc, char** argv ) { BasicTest(); MultipleSignalsConnectedTest(); return 0; } clam-1.4.0/test/NonPortedTests/TestEnvelopeExtractor.cxx0000644000000000000000000001526111076377340022112 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "EnvelopeExtractor.hxx" #include "EnvelopeGenerator.hxx" #if 0 #include "GnuplotSnapshot.hxx" #endif //#include "NodeTmpl.hxx" //#include "StreamBuffer.hxx" //#include "CircularStreamImpl.hxx" #include "WaveGenerator.hxx" #include "MonoAudioFileWriter.hxx" #include "Controller.hxx" #include #include #include namespace CLAMTest { using namespace CLAM; class EnvelopeExtractorTest { int mDataLength; int mSampleRate; int mFrameSize; int mIterations; EnvelopeExtractor *mpExtractor1; EnvelopeExtractor *mpExtractor2; EnvelopeGenerator *mpGenerator1; EnvelopeGenerator *mpGenerator2; WaveGenerator mGenerator; MonoAudioFileWriter mOutput1; MonoAudioFileWriter mOutput2; Controller mController; // NodeTmpl > mInputNode; // NodeTmpl > mOutputNode1; // NodeTmpl > mOutputNode2; void SendControls(int controls); bool TestConstruction(); bool TestConfiguration(); bool TestExecution(); bool TestDestruction(); public: EnvelopeExtractorTest(); bool Do(); }; EnvelopeExtractorTest::EnvelopeExtractorTest() : mDataLength(100000), mSampleRate(48000), mFrameSize(512), mIterations(100) { WaveGeneratorConfig wcfg; wcfg.SetSampleRate(mSampleRate); wcfg.SetFrequency(50.0); mGenerator.Configure(wcfg); Audio proto; proto.SetSampleRate(mSampleRate); MonoAudioFileWriterConfig fcfg; fcfg.SetSampleRate(mSampleRate); fcfg.SetTargetFile("test1.wav"); mOutput1.Configure(fcfg); fcfg.SetTargetFile("test2.wav"); mOutput2.Configure(fcfg); } bool EnvelopeExtractorTest::TestConstruction() { EnvExtractorConfig cfg; // You should add more constructions here, // using different configuration parameters, or // other constructors the class may provide. mpExtractor1 = new EnvelopeExtractor(); mpExtractor2 = new EnvelopeExtractor(cfg); mpGenerator1 = new EnvelopeGenerator(); mpGenerator2 = new EnvelopeGenerator(); return true; } bool EnvelopeExtractorTest::TestConfiguration() { EnvExtractorConfig cfg,cfg2; cfg.GetInterpolationPeriod().SetInitValue(2.5); cfg.GetIntegrationLength().SetInitValue(5.0); cfg.GetNormalLevel().SetInitValue(2.0); cfg.SetFrameSize(mFrameSize); cfg.SetSampleRate(mSampleRate); cfg.SetInterpolationType(EInterpolation::eSpline); cfg2 = cfg; mpExtractor1->Configure(cfg); mpExtractor2->Configure(cfg); mpExtractor1->Configure(cfg2); mpExtractor2->Configure(cfg2); EnvelopeGeneratorConfig ecfg1,ecfg2; ecfg1.SetDuration(1.0); ecfg1.SetFrameEnvelopes(true); ecfg1.SetSampleRate(mSampleRate); mpGenerator1->Configure(ecfg1); ecfg2 = ecfg1; mpGenerator2->Configure(ecfg2); return true; } void EnvelopeExtractorTest::SendControls(int controls) { if (controls & 0x1) { TData interpolation_period = double(rand())/double(RAND_MAX); mpExtractor1->cInterpolationPeriod.DoControl(interpolation_period); mpExtractor2->cInterpolationPeriod.DoControl(interpolation_period); } if (controls & 0x2) { TData integration_length = double(rand())/double(RAND_MAX); mpExtractor1->cIntegrationLength.DoControl(integration_length); mpExtractor2->cIntegrationLength.DoControl(integration_length); integration_length = integration_length + 10.0; } if (controls & 0x4) { TData normal_level = double(rand())/double(RAND_MAX); mpExtractor1->cNormalLevel.DoControl(normal_level); mpExtractor2->cNormalLevel.DoControl(normal_level); } if (controls & 0x8) { TData silence_level = double(rand())/double(RAND_MAX); mpExtractor1->cSilenceLevel.DoControl(silence_level); mpExtractor2->cSilenceLevel.DoControl(silence_level); } } bool EnvelopeExtractorTest::TestExecution() { Envelope envelope1,envelope2; ConnectPorts(mGenerator, 0, *mpExtractor1, 0); ConnectPorts(mGenerator, 0, *mpExtractor2, 0); ConnectPorts(*mpExtractor1, 0, *mpGenerator1, 0); ConnectPorts(*mpExtractor2, 0, *mpGenerator2, 0); ConnectPorts(*mpGenerator1, 0, mOutput1, 0); ConnectPorts(*mpGenerator2, 0, mOutput2, 0); // mInputNode.Configure(5*mFrameSize); // mOutputNode1.Configure(5*mFrameSize); // mOutputNode2.Configure(5*mFrameSize); mGenerator.Start(); mpExtractor1->Start(); mpExtractor2->Start(); mpGenerator1->Start(); mpGenerator2->Start(); mOutput1.Start(); mOutput2.Start(); for (int i=0; iDo(); mpExtractor2->Do(); mpGenerator1->Do(); mpGenerator2->Do(); mOutput1.Do(); mOutput2.Do(); if ( (i & 0x7) == 0x7) SendControls(int(4.0*rand()/(RAND_MAX+1.0))); } mGenerator.Stop(); mpExtractor1->Stop(); mpExtractor2->Stop(); mpGenerator1->Stop(); mpGenerator2->Stop(); mOutput1.Stop(); mOutput2.Stop(); return true; } bool EnvelopeExtractorTest::TestDestruction() { delete mpExtractor1; delete mpExtractor2; return true; } bool EnvelopeExtractorTest::Do() { bool res, ok = true; res = TestConstruction(); if (!res) { std::cerr << "Construction failed." << std::endl; ok = false; } res = TestConfiguration(); if (!res) { std::cerr << "Configuration failed." << std::endl; ok = false; } res = TestExecution(); if (!res) { std::cerr << "Execution failed." << std::endl; ok = false; } res = TestDestruction(); if (!res) { std::cerr << "Destruction failed." << std::endl; ok = false; } return ok; } } // main() return values: // 0: Test sucessful. // non-zero: Test Failed. int main() { try { CLAMTest::EnvelopeExtractorTest test; bool result = test.Do(); if (result==false) { std::cerr << "Failed." << std::endl; return 1; } } catch (std::exception &e) { std::cerr << "ERROR: Excepton: " << e.what() << std::endl << "Failed." << std::endl; return 1; } std::cerr << "Passed." << std::endl; return 0; } clam-1.4.0/test/NonPortedTests/TestFDFilterGen.cxx0000644000000000000000000001317211101735156020521 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "FDFilterGen.hxx" #include "Spectrum.hxx" #include "SpectrumConfig.hxx" #include using namespace CLAM; class FDControlsGenerator : public Processing { /** Private method called by the public Configure(cfg) method */ bool ConcreteConfigure(const ProcessingConfig& c) { CopyAsConcreteConfig(mConfig, c); return true; } public: FDControlsGenerator() : Gain("Gain",this), HighCutOff("High Cutoff Frecuency",this), LowCutOff("Low Cutoff Frecuency",this), PassBandSlope("Pass Band Slope",this), StopBandSlope("Stop Band Slope",this) {} const char * GetClassName() const {return "FDControlsGenerator";} bool Do(void) { Gain.SendControl(mConfig.GetGain()); HighCutOff.SendControl(mConfig.GetHighCutOff()); LowCutOff.SendControl(mConfig.GetLowCutOff()); PassBandSlope.SendControl(mConfig.GetPassBandSlope()); StopBandSlope.SendControl(mConfig.GetStopBandSlope()); return true; } const ProcessingConfig &GetConfig() const {return mConfig;} // public controls: FloatOutControl Gain, HighCutOff, LowCutOff, PassBandSlope, StopBandSlope; private: FDFilterGenConfig mConfig; }; void Set(Enum::tValue type, FDFilterGenConfig &cfg); void Set(Enum::tValue type, FDControlsGenerator &fil) { static FDFilterGenConfig cfg; Set(type,cfg); fil.Configure(cfg); } void Set(Enum::tValue type, FDFilterGenConfig &cfg) { cfg.SetSpectralRange(22050); switch(type) { case EFDFilterType::eLowPass: cfg.SetGain(1); cfg.SetLowCutOff(1000); cfg.SetStopBandSlope(3); break; case EFDFilterType::eHighPass: cfg.SetGain(1); cfg.SetHighCutOff(1000); cfg.SetPassBandSlope(3); break; case EFDFilterType::eBandPass: cfg.SetGain(1); cfg.SetHighCutOff(1000); cfg.SetPassBandSlope(3); cfg.SetLowCutOff(10000); cfg.SetStopBandSlope(3); break; case EFDFilterType::eStopBand: cfg.SetGain(1); cfg.SetLowCutOff(1000); cfg.SetStopBandSlope(3); cfg.SetHighCutOff(5000); cfg.SetPassBandSlope(3); break; } } void PrintPoints(Spectrum &spec) { BPF &bpf = spec.GetMagBPF(); std::cout << " " << bpf.Size() << " points BPF:" << std::endl; for (int i=0; i(gen.GetConfig()); cfg2.SetType(EFDFilterType(i)); gen.Configure(cfg2); Set(i,cfg); controls.Configure(cfg); gen.Configure(cfg2); gen.Start(); controls.Start(); controls.Do(); gen.Do(spec); controls.Stop(); gen.Stop(); PrintPoints(spec); } return 0; } int TestContrChanges(FDFilterGen &gen) { SpectrumConfig sets; SpecTypeFlags f; f.bMagPhaseBPF=true; f.bMagPhase=false; sets.SetType(f); Spectrum spec(sets); FDControlsGenerator controls; controls.GetOutControl(0).AddLink(gen.GetInControl(0)); controls.GetOutControl(1).AddLink(gen.GetInControl(1)); controls.GetOutControl(2).AddLink(gen.GetInControl(2)); controls.GetOutControl(3).AddLink(gen.GetInControl(3)); controls.GetOutControl(4).AddLink(gen.GetInControl(4)); // Sequence of control-changes and Do's of the generator // Available controls: Gain, HighCutOff, LowCutOff, PassBandSlope, StopBandSlope gen.Do(spec); if (gen.Do(spec)) throw Err("Do constant stream out error (should return false)"); controls.Gain.SendControl(0.8f); if (!gen.Do(spec)) throw Err("Do constant stream out error (should be true)"); if (gen.Do(spec)) throw Err("Do constant stream out error (should return false)"); return 0; } int main() { using namespace CLAM; try { int res=0; FDFilterGen gen; res = Test(gen); if (!res) res = TestContrChanges(gen); if (res) std::cerr << "Failed." << std::endl; else std::cerr << "Passed." << std::endl; return res; } catch(Err e) { e.Print(); return 1; } } clam-1.4.0/test/NonPortedTests/MTTestApp.hxx0000644000000000000000000000416310610720021017403 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef __MTTESTAPP__ #define __MTTESTAPP__ #include "GUIAudioApplication.hxx" #include "AudioIO.hxx" #include "Audio.hxx" #include "Oscillator.hxx" #include "OscillatorPresentation.hxx" #include "OscillatorGView.hxx" #include "AudioMultiplier.hxx" #include "AudioAdder.hxx" namespace CLAMTest { // Outer namespace symbol importing using CLAM::GUIAudioApplication; using CLAM::Audio; using CLAM::Oscillator; using CLAM::OscillatorConfig; using CLAM::AudioIn; using CLAM::AudioOut; using CLAM::AudioIOConfig; using CLAM::AudioManager; using CLAM::Err; using CLAM::AudioMultiplier; using CLAM::AudioAdder; class MTTestApp : public GUIAudioApplication { public: MTTestApp() : GUIAudioApplication(), finalize( false ) { } void UserMain(); // overriden method (GUI things) void AudioMain(); // overriden method for inserting our desired Audio Processing void AppCleanup(); static void SAudioThreadCleanUp( MTTestApp* pThis ); virtual ~MTTestApp() { } private: // Should class members be only shared objects between threads? bool finalize; // GUI thingies // These need to be declared here, since they are just in between CLAMGUI::AtomView< Oscillator > mCarView; CLAMGUI::AtomView< Oscillator > mModView; CLAMGUI::AtomView< Oscillator > mAmpModView; }; } #endif // MTTestApp.hxx clam-1.4.0/test/NonPortedTests/OctaveVector.hxx0000644000000000000000000002414710610720021020172 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include "Array.hxx" #include "Complex.hxx" #include "DataTypes.hxx" using CLAM::TData; using CLAM::Complex; namespace CLAMTest { using namespace CLAM; bool WriteOctaveVector(std::ofstream &f, const Array &array, const std::string &name) { // Vector header. f << "# Created by CLAM library" << std::endl << "# name: " << name.c_str() << std::endl << "# type: complex matrix" << std::endl << "# rows: 1" << std::endl << "# columns: " << array.Size() << std::endl; int i; for (i=0;i &array, const std::string &name) { // Vector header. f << "# Created by CLAM library" << std::endl << "# name: " << name.c_str() << std::endl << "# type: matrix" << std::endl << "# rows: 1" << std::endl << "# columns: " << array.Size() << std::endl; int i; for (i=0;i &array) { enum { eUnknown, // Reading vector header, about which we still know nothing. eMatch , // Reading vector header, with matching name eOther, // Reading vector header, with non-matching name or type eSkipData, // Skiping data. eData, // Reading our data. eError // Name not found, or found with wrong type } state = eUnknown; // const std::string state_str[] = { // std::string("eUnknown"), // std::string("eMatch"), // std::string("eOther"), // std::string("eSkipData"), // std::string("eData"), // std::string("eError") // }; std::string line; std::string name_line = "# name: "; name_line += name; name_line += '\n'; std::string type_start = "# type: "; std::string rows_start = "# rows: "; std::string columns_start = "# columns: "; const std::string good_type_line = "# type: matrix\n"; const std::string good_rows_line = "# rows: 1\n"; std::stringstream sstr; sstr << array.Size(); std::string good_columns_line = "# columns: "; good_columns_line += sstr.str(); // std::cerr << "Looking for: " << std::endl // << name_line // << good_type_line // << good_rows_line // << good_columns_line; std::stringstream ss; int pos; TData *buffer = array.GetPtr(); // NOTE: The parser asumes that there is always "type", "rows" // and "columns" fields in the header of a vector definition. // f.seekg(0); while (f) { std::getline(f,line); // std::cerr << " R: " << line << std::endl; switch(state) { case eUnknown: if (line[0]!='#') { // End of header state=eSkipData; break; } if (line == name_line) { state=eMatch; break; } if (line != good_type_line && line.substr(0,type_start.size())==type_start ) { state=eOther; break; } if (line != good_rows_line && line.substr(0,rows_start.size())==rows_start) { state=eOther; break; } if (line != good_columns_line && line.substr(0,columns_start.size()) == columns_start) { state=eOther; break; } break; case eOther: if (line[0]!='#') { // End of header state=eSkipData; break; } if (line == name_line) throw(Err("LoadOctaveTData: found vector with wrong parameters")); break; case eSkipData: if (line[0]=='#') { // First header line. We can skip it. state=eUnknown; break; } break; case eData: throw(Err("CLAM: Inconsistent state")); //Should never get here case eMatch: if ( line != good_type_line && line.substr(0,type_start.size())==type_start ) throw(Err("LoadOctaveTData: found vector with wrong type")); if (line != good_rows_line && line.substr(0,rows_start.size())==rows_start) throw(Err("LoadOctaveTData: found vector with wrong number of rows")); if (line != good_columns_line && line.substr(0,columns_start.size()) == columns_start) throw(Err("LoadOctaveTData: found vector with wrong number of columns")); if (line[0]=='#') // End of header break; ss.str(line); ss.seekg(0); pos=0; while (1) { TData point; ss >> point; if (ss.eof()) if (pos == array.Size()-1) return true; else { std::cerr << "Eof found while reading pos " << pos << std::endl; return false; } if (ss.good()) if (pos == array.Size()-1) { std::cerr << "pos = << "< &array) { enum { eUnknown, // Reading vector header, about which we still know nothing. eMatch , // Reading vector header, with matching name eOther, // Reading vector header, with non-matching name or type eSkipData, // Skiping data. eData, // Reading our data. eError // Name not found, or found with wrong type } state = eUnknown; // const std::string state_str[] = { // std::string("eUnknown"), // std::string("eMatch"), // std::string("eOther"), // std::string("eSkipData"), // std::string("eData"), // std::string("eError") // }; std::string line; std::stringstream sstr; sstr.str(name); sstr.seekp(name.size()); // sstr << std::endl; std::string name_line = "# name: "; name_line += sstr.str(); std::string type_start = "# type: "; std::string rows_start = "# rows: "; std::string columns_start = "# columns: "; sstr.str(""); // sstr << std::endl; std::string good_type_line = "# type: complex matrix"; good_type_line += sstr.str(); std::string good_rows_line = "# rows: 1"; good_rows_line += sstr.str(); sstr.str(""); sstr << array.Size();// << std::endl; std::string good_columns_line = "# columns: "; good_columns_line += sstr.str(); // std::cerr << "Looking for: " << std::endl // << name_line // << good_type_line // << good_rows_line // << good_columns_line; std::stringstream ss; int pos; Complex *buffer = array.GetPtr(); // NOTE: The parser asumes that there is always "type", "rows" // and "columns" fields in the header of a vector definition. // f.seekg(0); while (f) { std::getline(f,line); // std::cerr << " R: " << line << std::endl; switch(state) { case eUnknown: if (line[0]!='#') { // End of header state=eSkipData; break; } if (line == name_line) { state=eMatch; break; } if (line != good_type_line && line.substr(0,type_start.size())==type_start ) { state=eOther; break; } if (line != good_rows_line && line.substr(0,rows_start.size())==rows_start) { state=eOther; break; } if (line != good_columns_line && line.substr(0,columns_start.size()) == columns_start) { state=eOther; break; } break; case eOther: if (line[0]!='#') { // End of header state=eSkipData; break; } if (line == name_line) throw(Err("LoadOctaveTData: found vector with wrong parameters")); break; case eSkipData: if (line[0]=='#') { // First header line. We can skip it. state=eUnknown; break; } break; case eData: throw(Err("CLAM: Inconsistent state")); //Should never get here case eMatch: if ( line != good_type_line && line.substr(0,type_start.size())==type_start ) throw(Err("LoadOctaveTData: found vector with wrong type")); if (line != good_rows_line && line.substr(0,rows_start.size())==rows_start) throw(Err("LoadOctaveTData: found vector with wrong number of rows")); if (line != good_columns_line && line.substr(0,columns_start.size()) == columns_start) throw(Err("LoadOctaveTData: found vector with wrong number of columns")); if (line[0]=='#') // End of header break; ss.str(line); ss.seekg(0); pos=0; while (1) { std::string point; ss >> point; std::stringstream spoint(point); char c; TData real,imag; spoint >> c >> real >> c >> imag >> c; if (ss.bad()) { std::cerr << "Input error" << std::endl; return false; } buffer[pos++]=Complex(real,imag); if (ss.good()) if (pos == array.Size()) { std::cerr << "pos = << "< /* #include "BPFView.hxx" #include "Builder.hxx" #define function_left_limit 0 #define function_top_limit 100 #define function_right_limit 2000 #define function_bottom_limit 0*/ #include "Point.hxx" #include "BPF.hxx" #include "GlobalEnums.hxx" #include #include //#include "XMLTestHelper.hxx" using namespace CLAM; float GetXValue(BPF& testBPF,int index); float GetValue(BPF& testBPF,float xValue); float GetValueFromIndex(BPF& testBPF,int index); void DumpOrderedBPFPoints(FILE* pFile, BPF &bpf, const char* title); void DumpRandomBPFPoints(FILE* pFile, BPF &bpf, const char* title); void DumpOrderedBPF(FILE* pFile, BPF &bpf, const char* title, unsigned int points=0); void DumpRandomBPF(FILE* pFile, BPF &bpf, const char* title, unsigned int points=0); typedef enum { eLinear, eRandom } ETestType; void SetTestBPF(BPF &bpf, ETestType,int size=20); int main() { try{ EInterpolation testInt=EInterpolation::eLinear; srand((unsigned)time(NULL)); int size = 50; int points = 500; BPF testBPF; FILE *pFile; pFile = fopen( "BPFText.txt", "w" ); fprintf(pFile,"\n# ***************************BPF TEST**************************\n\n\n"); fprintf(pFile,"\n# ----------------------Inserting points in order---------------\n\n\n"); fprintf(pFile,"\n# Inserting %d points\n",size); /*Note the Y values will always be between 0 and 1*/ SetTestBPF(testBPF,eLinear,size); DumpOrderedBPFPoints(pFile,testBPF,"Points inserted to the BPF"); DumpOrderedBPF(pFile,testBPF,"Linear Interpolation: Getting points in order",points); DumpRandomBPF (pFile,testBPF,"Linear Interpolation: Getting points in random order",points); testInt=EInterpolation::ePolynomial2; testBPF.SetIntpType(testInt); DumpOrderedBPF(pFile,testBPF,"Parabolic Interpolation",points); testInt=EInterpolation::ePolynomial3; testBPF.SetIntpType(testInt); DumpOrderedBPF(pFile,testBPF,"3rd Order Polynomial Interpolation",points); testInt=EInterpolation::eSpline; testBPF.SetIntpType(testInt); testBPF.UpdateSplineTable(); DumpOrderedBPF(pFile,testBPF,"3rd Order Spline Interpolation",points); /*Now let's see what happens inserting random points*/ fprintf(pFile,"\n# --------------------Inserting points in random order--------------\n\n\n"); BPF testBPF2; SetTestBPF(testBPF2,eRandom,size); DumpOrderedBPFPoints(pFile,testBPF2,"Points inserted to the BPF"); DumpOrderedBPF(pFile,testBPF2,"Linear Interpolation: Getting points in order",points); DumpRandomBPF(pFile,testBPF2,"Linear Interpolation: Getting points in random order",points); testInt=EInterpolation::ePolynomial2; testBPF2.SetIntpType(testInt); DumpOrderedBPF(pFile,testBPF2,"Parabolic Interpolation",points); testInt=EInterpolation::ePolynomial3; testBPF2.SetIntpType(testInt); DumpOrderedBPF(pFile,testBPF2,"3rd Order Polynomial Interpolation",points); testInt=EInterpolation::eSpline; testBPF2.SetIntpType(testInt); testBPF2.UpdateSplineTable(); DumpOrderedBPF(pFile,testBPF2,"3rd Order Spline Interpolation",points); /* Now we test the spline a bit harder... */ testBPF2.SetLeftDerivative(0.1); testBPF2.SetRightDerivative(0.1); testBPF2.UpdateSplineTable(); DumpOrderedBPF(pFile,testBPF2,"3rd Order Spline Interpolation with flat borders",points); /* // if you want to view your BPF, add the necessary files and... BPFView myBPFView; BPFViewConfig cfg; cfg.SetLabel( "BPF WATCHER"); cfg.SetScreenArea( CLAM::Recti(100, 100, 300, 240 ) ); // function_left_limit cfg.SetFOV( FOV( function_left_limit, function_top_limit, function_right_limit, function_bottom_limit ) ); myBPFView.BindWith( &testBPF2, cfg ); Builder* pb = CLAM::Builder::GetInstance("FLTK"); GUIObject* gui = pb->GetGUI(); do { gui->Refresh(0.0); }while(!gui->End()); */ fclose(pFile); } catch(Err err) { err.Print(); return 1; } return 0; } void SetTestBPF(BPF &testBPF,ETestType test, int size) { int n,index; float xValue,yValue; std::vector values(size); TData delta = 1.0/(size-1); TData pos=0.0; testBPF.SetSize(0); testBPF.Resize(0); switch (test) { case eLinear: for(n=0;n &GetPointArray( BPF& testBPF) {return testBPF.GetPointArray();} TIndex GetPosition(BPF& testBPF,float x) {return testBPF.GetPosition(x);} TSize GetStep(BPF& testBPF) {return testBPF.GetStep();} float GetValue(BPF& testBPF,float xValue) {return testBPF.GetValue(xValue);} float GetValue (BPF& testBPF,float x,const EInterpolation& eInterpolation) {return testBPF.GetValue(x,eInterpolation);} float GetValueFromIndex(BPF& testBPF,int index) {return testBPF.GetValueFromIndex(index);} float GetXValue(BPF& testBPF,int index) {return testBPF.GetXValue(index);} void Init(BPF& testBPF){testBPF.Init();} void Insert(BPF& testBPF,const Point &point) {testBPF.Insert(point);} void Insert(BPF& testBPF,float x,float y){testBPF.Insert(x,y);} void Resize (BPF& testBPF,TSize newSize){testBPF.Resize(newSize);} void SetIntpType(BPF& testBPF,const EInterpolation& eInterpolation) {testBPF.SetIntpType(eInterpolation);} void SetSize (BPF& testBPF,TSize newSize){testBPF.SetSize(newSize);} void SetStep(BPF& testBPF,TSize step){testBPF.SetStep(step);} void SetValue(BPF& testBPF,TIndex index,float y) {testBPF.SetValue(index,y);} void SetXValue(BPF& testBPF,TIndex index,float x) {testBPF.SetXValue(index,x);} TSize Size(BPF& testBPF) {return testBPF.Size();} void UpdateSplineTable(BPF& testBPF){testBPF.UpdateSplineTable();} clam-1.4.0/test/NonPortedTests/TestWindowing.cxx0000644000000000000000000000626610610720021020370 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include "AudioMultiplier.hxx" #include "CircularShift.hxx" #include "WindowGenerator.hxx" #include "TestUtils.hxx" using namespace CLAM; using namespace CLAMTest; using namespace TestUtils; void DumpAudio(Audio& a) { int i; int size = a.GetSize(); for (i=0;i #include //rand() #include "SpectrumProduct.hxx" #include "TestUtils.hxx" #include "OctaveVector.hxx" //TODO: To be unquoted when we use gcc 3.0 //#include namespace CLAMTest { static const unsigned int ArraySize=40; // Loads the vectors from a file, if they have not been previously loaded, // and sets the arguments to the loaded values. bool SetTestVectors(Spectrum &s1, Spectrum &s2, Spectrum &s3) { bool remove1=false,remove2=false,remove3=false; static bool loaded=false; static Spectrum orig1,orig2,orig3; if (!loaded) { std::ifstream file("SpectrumProductTest.data"); SpecTypeFlags f; f.bMagPhase=false; f.bComplex=true; orig1.SetSize(ArraySize); orig2.SetSize(ArraySize); orig3.SetSize(ArraySize); orig1.SetType(f); orig2.SetType(f); orig3.SetType(f); if (file) { std::cerr << "Loading Input1..." << std::endl; if (!CLAMTest::LoadOctaveComplexVector(file,"Input1",orig1.GetComplexArray())) { std::cerr << "Could not find Input1 vector in input!" << std::endl; return false; } std::cerr << "Loading Input2..." << std::endl; if (!CLAMTest::LoadOctaveComplexVector(file,"Input2",orig2.GetComplexArray())) { std::cerr << "Could not find Audio vector in input!" << std::endl; return false; } std::cerr << "Loading Output..." << std::endl; if (!CLAMTest::LoadOctaveComplexVector(file,"Output",orig3.GetComplexArray())) { std::cerr << "Could not find Audio vector in input!" << std::endl; return false; } file.close(); } else { std::cerr << "Generating Inputs and output..." << std::endl; for (int i = 0; i < ArraySize; i++) { orig1.GetComplexArray().GetPtr()[i] = Complex(10.0*(TData)rand()/(TData)RAND_MAX, 10.0*(TData)rand()/(TData)RAND_MAX); orig2.GetComplexArray().GetPtr()[i] = Complex(10.0*(TData)rand()/(TData)RAND_MAX, 10.0*(TData)rand()/(TData)RAND_MAX); orig3.GetComplexArray().GetPtr()[i] = orig1.GetComplexArray().GetPtr()[i] * orig2.GetComplexArray().GetPtr()[i]; } } loaded=true; } SpecTypeFlags spec; s1.GetType(spec); if (!spec.bComplex) { spec.bComplex=1; s1.SetType(spec); remove1=true; } s2.GetType(spec); if (!spec.bComplex) { spec.bComplex=1; s2.SetType(spec); remove2=true; } s3.GetType(spec); if (!spec.bComplex) { spec.bComplex=1; s3.SetType(spec); remove3=true; } s1.SetComplexArray(orig1.GetComplexArray()); s2.SetComplexArray(orig2.GetComplexArray()); s3.SetComplexArray(orig3.GetComplexArray()); spec.bMagPhase=spec.bPolar=spec.bMagPhaseBPF=false; s1.SynchronizeTo(spec); s2.SynchronizeTo(spec); s3.SynchronizeTo(spec); if (remove1) { s1.GetType(spec); spec.bComplex=false; s1.SetType(spec); } if (remove2) { s2.GetType(spec); spec.bComplex=false; s2.SetType(spec); } if (remove3) { s3.GetType(spec); spec.bComplex=false; s3.SetType(spec); } return true; } void SetPrototypes(int proto, Spectrum &s) { SpecTypeFlags f; f.bComplex=proto&(1<<(int)SpecTypeFlags::eComplex); f.bPolar=proto&(1<<(int)SpecTypeFlags::ePolar); f.bMagPhase=proto&(1<<(int)SpecTypeFlags::eMagPhase); f.bMagPhaseBPF=proto&(1<<(int)SpecTypeFlags::eMagPhaseBPF); s.SetType(f); } std::string ProtoName(int proto) { std::string str; for (int i=0; i<4; i++) if (proto&(1<::epsilon()*TData(1e3); product.Start(); cfg.AddBPFSize(); cfg.UpdateData(); cfg.SetSize(ArraySize); cfg.SetBPFSize(ArraySize); Spectrum in1(cfg),in2(cfg),out(cfg),out_good(cfg); for (proto1=1; proto1<16; proto1++) for (proto2=1; proto2<16; proto2++) for (proto3=1; proto3<16; proto3++) { std::cerr << "Test " << count++ << '(' << proto1 << ',' << proto2 << ',' << proto3 << ')' < max_err) return false; std::cerr.flush(); } return true; } } int main() { try { CLAM::SpectrumProduct prod; bool res = CLAMTest::TestProduct(prod); if (res) std::cerr << std::endl << "Passed." << std::endl; else std::cerr << std::endl << "Failed." << std::endl; return !res; } catch (CLAM::Err e) { e.Print(); } } clam-1.4.0/test/NonPortedTests/TestUtils.hxx0000644000000000000000000000457610610720021017532 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _TEST_UTILS_H #define _TEST_UTILS_H #include "SpectrumComp.hxx" #include "Audio.hxx" #include "Err.hxx" #include "DataTypes.hxx" using CLAM::Err; using CLAM::TData; using CLAM::Spectrum; using CLAM::Array; namespace CLAMTest { class TestError : public Err { public: TestError(const char* description) : Err(description) {}; }; namespace TestUtils { TData MaxDiff(const CLAM::Audio &a1,const CLAM::Audio &a2); bool operator!=(const CLAM::Audio &a1, const CLAM::Audio &a2); bool operator==(const CLAM::Audio &a1, const CLAM::Audio &a2); bool operator!=(Spectrum &s1, Spectrum &s2); bool operator==(Spectrum &s1, Spectrum &s2); TData MaxDiff(const CLAM::Audio &a1,const CLAM::Audio &a2) { TData diff = 0.0, max_diff = 0.0; int i, size = a1.GetSize(); if (size != a2.GetSize()) throw TestError("Audio sizes differ in comparision."); const Array &samples1 = a1.GetBuffer(); const Array &samples2 = a2.GetBuffer(); for (i=0; i max_diff) max_diff = diff; } return max_diff; } bool operator!=(const CLAM::Audio &a1, const CLAM::Audio &a2) { if (MaxDiff(a1,a2) > 0.001) return true; return false; } bool operator!=(Spectrum &s1, Spectrum &s2) { if (TestUtils::MaxDiff(s1,s2) > 0.001) return true; return false; } bool operator==(const CLAM::Audio &a1, const CLAM::Audio &a2) { return !(a1!=a2); } bool operator==(Spectrum &s1, Spectrum &s2) { return !(s1!=s2); } } } #endif clam-1.4.0/test/NonPortedTests/TestArray2.cxx0000644000000000000000000003552410610720021017562 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "Array.hxx" #include "Assert.hxx" #include #include // for rand #include #include using std::cout; using std::endl; using std::cerr; using std::ostream; using std::istream; using CLAM::Err; namespace CLAMTest { using namespace CLAM; template class MyArray : public std::vector { typedef std::vector Super; public: typedef typename std::vector::iterator iterator; typedef typename std::vector::const_iterator const_iterator; MyArray(TSize size = 0) : std::vector(size){} void Init() { Super::reserve(0); Super::resize(0); } MyArray(T* ptr,int size = 0) { throw(Err("MyArray::MyArray(T*): Not implemented")); } bool OwnsMemory() const { return true; } int Size() const { return Super::size(); } int SizeInBytes() const { return Super::size() * sizeof(T); } int AllocatedSize() const { return Super::capacity(); } int AllocatedSizeInBytes() const { return Super::capacity() * sizeof(T); } void SetSize(int size) { Super::resize(size); } void Resize(int size) { Super::reserve(size); } const T* GetPtr(void) const {return &(*this)[0];} T* GetPtr(void) {return &(*this)[0];} // void SetPtr(T* ptr) { // throw(Err("MyArray::SetPtr(T*): Not implemented")); // } void AddElem(const T& elem) {Super::push_back(elem);} void InsertElem(int pos, const T& elem) {Super::insert(iterator(&(Super::operator[](pos))),elem);} void DeleteElem(int where) { Super::erase(iterator(&Super::operator[](where)));} MyArray& operator += (const MyArray& src) { Super::insert(Super::end(),src.begin(),src.end()); return *this; } void Apply( T (*f)(T,int),int parameter ){ int i; int s=Super::size(); for (i=0; i>(istream &in, FatOne &d) { unsigned int i; in >> i; d.Set(i); return in; } ostream &operator<<(ostream &out, const FatOne &d) { out << d.Val(); return out; } class SelfRefering { int data; SelfRefering *me; public: // Default constructor: initializes self-reference. int Data() const {return data;} void Data(int i) {data=i;} SelfRefering(int i=0) { data = i; me = this; } // Copy constructor: must be implemented to keep the self-reference consistent. SelfRefering(const SelfRefering& src) { data=src.data; me = this; } // Copy operator: same as for the constructor. SelfRefering &operator = (const SelfRefering& src) { data=src.data; me = this; return *this; } // The destructor: is everything ok? ~SelfRefering() { if (me != this) throw(CLAM::Err("SelfRefering error: invalid self reference")); } bool operator ==(const SelfRefering& src) const { return Data() == src.Data(); } bool operator !=(const SelfRefering& src) const { return Data() != src.Data(); } }; istream &operator>>(istream &in, SelfRefering &d) { unsigned int i; in >> i; d.Data(i); return in; } ostream &operator<<(ostream &out, const SelfRefering &d) { out << d.Data(); return out; } template class TestArray { TArray &victim; static int mMaxSize; long mIterations; long mMaxIterations; public: TestArray(TArray &a) : victim(a) {} typedef enum { eAccess = 0, eInsert, eRemove, eResize, eSetSize, eStep, eCopy, eConcat, eConstruct, NUMTypes } ETestType; bool TestAccess(); bool TestInsert(); bool TestAdd(); bool TestRemove(); bool TestResize(); bool TestSetSize(); bool TestStep(); bool TestCopy(); bool TestConcat(); bool TestConstruct(); bool Test(ETestType type) { switch(type) { case eAccess: return TestAccess(); case eInsert: return TestInsert(); case eRemove: return TestRemove(); case eResize: return TestResize(); case eSetSize: return TestSetSize(); case eStep: return TestStep(); case eCopy: return TestCopy(); case eConcat: return TestConcat(); case eConstruct: return TestConstruct(); default: return false; } } void TestFailed() { cout << "Test Failed" << endl; } bool Do(int max, int init=0) { mIterations = init; mMaxIterations = max; int tnum; while (mIterations < mMaxIterations) { cout << mIterations << ": "; tnum = (int) (double(NUMTypes)*rand()/(RAND_MAX+1.0)); if (!Test(ETestType(tnum))) return false; mIterations ++; } return true; } }; template int TestArray::mMaxSize = 16; template bool TestArray::TestAccess() { int i; int size = victim.Size(); cout << "Testing access with size " << size << endl; T * backup = new T[size]; for (i=0; i=0;i--) { victim[i]=T(0); if (victim[i] != T(0)) { TestFailed(); return false; } } for (i=0; i bool TestArray::TestAdd() { cout << "Testing addition " << endl; int pos = victim.Size(); T elem(rand()); victim.AddElem(elem); if (victim[pos] != elem) { TestFailed(); return false; } return true; } template bool TestArray::TestInsert() { if (victim.Size() == 0) { cout << "Test insertion skipped" << endl; return true; } #ifdef CLAM_TEST_DEBUG_CHECKS int pos = (int) (double(victim.Size()-1)*1.2*rand()/(RAND_MAX+1.0)); #else int pos = (int) (double(victim.Size()-1)*rand()/(RAND_MAX+1.0)); #endif int rep = int(1+(3.0*rand()/(RAND_MAX+1.0))); cout << "Testing " << rep << " insertion(s) at pos " << pos << endl; try { while (rep--) { T elem; victim.InsertElem(pos,elem); if (victim[pos] != elem) { TestFailed(); return false; } } } catch (Err &e) { if ( strcmp(e.what(),TArray::msgInsertOutOfRange) ) { cout << " Exception thrown in InsertElem: " << e.what() << endl; TestFailed(); return false; } if ( pos < victim.Size() ) { cout << " IndexOutOfRange thrown after correct InsertElem call!" << endl; TestFailed(); return false; } return true; } if (pos >= victim.Size()) { cout << " Exception not thrown after incorrect InsertElem call!" << endl; TestFailed(); return false; } return true; } template bool TestArray::TestRemove() { int size = victim.Size(); if (!size) { cout << "Test remove skipped" << endl; return true; } int pos = int(double(size)*rand()/(RAND_MAX+1.0)); int rep = int(1+(3.0*rand()/(RAND_MAX+1.0))); if (rep > (size-pos)) rep = size-pos; cout << "Testing " << rep << " deletion(s) at pos " << pos << endl; while (rep--) { victim.DeleteElem(pos); if (victim.Size() != size-1) { TestFailed(); return false; } size--; } return true; } template bool TestArray::TestResize() { int new_size = int(double((victim.AllocatedSize()+1)*2)*rand()/(RAND_MAX+1.0)); if (new_size > mMaxSize) new_size = mMaxSize; int rep = int(1+(3.0*rand()/(RAND_MAX+1.0))); cout << "Testing " << rep << " resize(s) to size " << new_size << endl; while (rep--) { victim.Resize(new_size); } return true; } template bool TestArray::TestSetSize() { #ifdef CLAM_TEST_DEBUG_CHECKS int new_size = int(double((victim.AllocatedSize()+1)*2)*rand()/(RAND_MAX+1.0)); #else int new_size = int(double(victim.AllocatedSize() )*rand()/(RAND_MAX+1.0)); #endif int rep = int(1+(3.0*rand()/(RAND_MAX+1.0))); cout << "Testing " << rep << " SetSize(s) to size " << new_size << endl; try { while (rep--) { victim.SetSize(new_size); } } catch (Err &e) { if ( strcmp(e.what(),TArray::msgSetSizeOutOfRange) ) { cout << " Exception thrown in SetSize: " << e.what() << endl; TestFailed(); return false; } if ( new_size <= victim.AllocatedSize() ) { cout << " IndexOutOfRange thrown after correct SetSize call!" << endl; TestFailed(); return false; } return true; } if (victim.Size() > victim.AllocatedSize()) { cout << " Size is bigger than allocated size!" << endl; TestFailed(); return false; } return true; } template bool TestArray::TestStep() { cout << "TODO: TestStep not implemented!!!" << endl; return true; } template bool TestArray::TestConcat() { int old_size = victim.Size(); int new_size = int(double((old_size+1)*2)*rand()/(RAND_MAX+1.0)); int i; if (new_size > mMaxSize) new_size = mMaxSize; int rep = int(1+(3.0*rand()/(RAND_MAX+1.0))); cout << "Testing " << rep << " concat(s) with size " << new_size << endl; TArray new_array; new_array.Resize(new_size); new_array.SetSize(new_size); for (i=0;i bool TestArray::TestCopy() { TArray new_array; int new_size = int(double((victim.Size()+1)*2)*rand()/(RAND_MAX+1.0)); int i; if (new_size > mMaxSize) new_size = mMaxSize; new_array.Resize(new_size); new_array.SetSize(new_size); int rep = int(1+(3.0*rand()/(RAND_MAX+1.0))); cout << "Testing " << rep << " copy(s) with size " << new_size << endl; for (i=0;i bool TestArray::TestConstruct() { if (mIterations == mMaxIterations) return 1; cout << "Testing constructor..." << endl; TArray *new_array = new TArray(victim); TestArray new_test(*new_array); int end_iter = mIterations + 100; if (end_iter > mMaxIterations) end_iter = mMaxIterations; if (!new_test.Do(end_iter,mIterations)) return false; delete new_array; mIterations = end_iter; return true; } } int main() { srand(333); // srand(time(0)); using namespace CLAMTest; try { // MyArray w; // TestArray > testA(w); // if (!testA.Do(50)) { // std::cout << "Failed." << std::endl; // return 1; // } // MyArray x; // TestArray > testB(x); // if (!testB.Do(50)) { // std::cout << "Failed." << std::endl; // return 1; // } // MyArray y; // TestArray > testC(y); // if (!testC.Do(50)) { // std::cout << "Failed." << std::endl; // return 1; // } // MyArray z; // TestArray > testD(z); // if (!testD.Do(50)) { // std::cout << "Failed." << std::endl; // return 1; // } std::cout << std::endl << "Testing char array" << std::endl; Array a; TestArray > test1(a); if (!test1.Do(10000)) { std::cout << "Failed." << std::endl; return 1; } std::cout << std::endl << "Testing double array" << std::endl; Array b; TestArray > test2(b); if (!test2.Do(10000)) { std::cout << "Failed." << std::endl; return 1; } std::cout << std::endl << "Testing self-referencing array" << std::endl; Array c; TestArray > test3(c); if (!test3.Do(10000)) { std::cout << "Failed." << std::endl; return 1; } std::cout << std::endl << "Testing dinamic memory array" << std::endl; Array d; TestArray > test4(d); if (!test4.Do(10000)) { std::cout << "Failed." << std::endl; return 1; } std::cout << "Passed." << std::endl; return 0; } catch (std::exception &e) { std::cout << e.what() << std::endl << "Failed." << std::endl; return 1; } catch (...) { std::cout << "Unknown Exception!!!" << std::endl << "Failed." << std::endl; return 1; } } clam-1.4.0/test/NonPortedTests/PhantomBufferTest.cxx0000644000000000000000000001210510610720021021150 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "PhantomBuffer.hxx" #include namespace CLAMTest { template class DataChunk { T data[N]; public: DataChunk() {}; DataChunk(T val); T* Address() { return data; } T &operator[](int i) { return data[i]; } }; template DataChunk::DataChunk(T val) { for (unsigned i=0; i class PhantomBufferTest { CLAM::PhantomBuffer *mpObject1; CLAM::PhantomBuffer *mpObject2; bool TestConstruction(); bool TestUsage(); bool TestDestruction(); public: bool Do(); }; template bool PhantomBufferTest::TestConstruction() { mpObject1 = new CLAM::PhantomBuffer(); mpObject2 = new CLAM::PhantomBuffer(*mpObject1); return true; } template bool PhantomBufferTest::TestUsage() { mpObject1->Resize(0,0,0); mpObject1->Resize(1,1,0); mpObject1->Resize(1,1,1); mpObject1->Resize(2,1,0); mpObject1->Resize(2,1,1); mpObject1->Resize(2,1,2); mpObject1->Resize(2,2,2); mpObject1->Resize(2,2,1); mpObject1->Resize(2,2,0); mpObject2->Resize(0,0,0); mpObject2->Resize(10,1,0); mpObject2->Resize(10,1,1); mpObject2->Resize(20,1,0); mpObject2->Resize(20,1,1); mpObject2->Resize(20,1,2); mpObject2->Resize(20,2,2); mpObject2->Resize(20,2,1); mpObject2->Resize(20,2,0); int i; double *read; for (i = 0; i<22-5; i++) { DataChunk data(double(100.0+i)); mpObject2->FulfilsInvariant(); mpObject2->Write(i,5,data.Address()); mpObject2->FulfilsInvariant(); read = mpObject2->Read(i,5); for (int j=0; j<5; j++) if (data[j] != read[j]) { std::cerr << "TestUsage(): Written and read data differ!\n"; return false; } mpObject2->FulfilsInvariant(); } for (i = 22-9; i>=0; i--) { DataChunk data(double(2000+i)); mpObject2->FulfilsInvariant(); mpObject2->Write(i,8,data.Address()); mpObject2->FulfilsInvariant(); read = mpObject2->Read(i,8); for (int j=0; j<8; j++) if (data[j] != read[j]) { std::cerr << "TestUsage(): Written and read data differ!\n"; return false; } mpObject2->FulfilsInvariant(); } int logical_size = 21; int phantom_size = 2; for (i=0; i<100; i++) { DataChunk data(double(30000+i)); mpObject2->FulfilsInvariant(); mpObject2->Write(0,10,data.Address()); mpObject2->FulfilsInvariant(); mpObject2->Resize(logical_size++, phantom_size++, 0); mpObject2->FulfilsInvariant(); read = mpObject2->Read(1,10); mpObject2->FulfilsInvariant(); for (int j=0; j<10; j++) if (data[j] != read[j]) { std::cerr << "TestUsage(): Written and read data differ!\n"; return false; } } int size_increment = 1; int write_pos = 0; for (i=0; i<100; i++) { DataChunk data(double(40000+i)); mpObject2->FulfilsInvariant(); mpObject2->Write(write_pos,10,data.Address()); mpObject2->FulfilsInvariant(); mpObject2->Resize(logical_size, phantom_size, write_pos); mpObject2->FulfilsInvariant(); read = mpObject2->Read(write_pos + size_increment,10); mpObject2->FulfilsInvariant(); for (int j=0; j<10; j++) if (data[j] != read[j]) { std::cerr << "TestUsage(): Written and read data differ!\n"; return false; } size_increment++; logical_size += size_increment; phantom_size += 2; write_pos += size_increment; } return true; } template bool PhantomBufferTest::TestDestruction() { delete mpObject1; delete mpObject2; return true; } template bool PhantomBufferTest::Do() { bool res, ok = true; res = TestConstruction(); if (!res) { std::cerr << "Construction failed." << std::endl; ok = false; } res = TestUsage(); if (!res) { std::cerr << "Usage failed." << std::endl; ok = false; } res = TestDestruction(); if (!res) { std::cerr << "Destruction failed." << std::endl; ok = false; } return ok; } } int main() { try { CLAMTest::PhantomBufferTest test; bool result = test.Do(); if (result==false) { std::cerr << "Failed." << std::endl; return 1; } } catch (std::exception &e) { std::cerr << "ERROR: Excepton: " << e.what() << std::endl << "Failed." << std::endl; return 1; } std::cerr << "Passed." << std::endl; return 0; } clam-1.4.0/test/NonPortedTests/TestError.cxx0000644000000000000000000000474211076377340017534 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "Err.hxx" #include "ErrDynamicType.hxx" #include "ErrProcessingObj.hxx" #include "ErrOpenFile.hxx" #include "ErrOutOfMemory.hxx" using CLAM::Err; using CLAM::ErrDynamicType; using CLAM::ErrProcessingObj; using CLAM::ErrOpenFile; using CLAM::ErrOutOfMemory; namespace CLAMTest { using namespace CLAM; template class ExceptionTester { void Ok() { std::cout << "."; } void Fail() { std::cout << "\nFailed!" << std::endl; exit(1); } public: ExceptionTester() { PlainTest(); GeneralTest(); EmbedTest(); } void PlainTest() { try { throw T("Plain"); } catch (T& e) { e.Print(); Ok(); } catch(...) { Fail(); } } void GeneralTest() { try { throw T("General"); } catch (Err& e) { e.Print(); Ok(); } catch(...) { Fail(); } } void EmbedTest() { try { try { throw T("Embed"); } catch (T &orig) { Err myErr("Trying nested exceptions"); myErr.Embed(orig); throw(myErr); } catch (...) { Fail(); } } catch (Err &e) { e.Print(); Ok(); } catch (...) { Fail(); } } }; } int main() { using namespace CLAMTest; try { ExceptionTester(); ExceptionTester(); ExceptionTester(); ExceptionTester(); // ExceptionTester(); std::cout << "Passed." << std::endl; return 0; } catch (Err&e) { e.Print(); std::cout << "Failed." << std::endl; return 1; } catch (...) { std::cout << "Unknown exception!. Failed." << std::endl; return 1; } } clam-1.4.0/test/NonPortedTests/TestAssert.cxx0000644000000000000000000000340710610720021017656 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "Assert.hxx" #include int main (void) { CLAM_BEGIN_CHECK std::cout << "Executing the check" << std::endl; CLAM_END_CHECK CLAM_BEGIN_DEBUG_CHECK std::cout << "Executing the debug check" << std::endl; CLAM_END_DEBUG_CHECK try { CLAM_ASSERT(((std::cout<<"ExecutingAssertTrue"< using CLAM::TData; using CLAM::Polar; using CLAM::Point; using CLAM::Complex; using CLAM::BPF; using CLAM::EScale; using CLAM::SpectrumConfig; using CLAM::Spectrum; using CLAM::SpecTypeFlags; namespace CLAMTest { class SpectrumTest { std::string reason; int confidx; int protoidx; bool SpecConfCmp(const SpectrumConfig &c1,const SpectrumConfig &c2); void ResetConfGen(); void SetFlagsLowLevel(Spectrum &s); SpectrumConfig GenConfig(); void ResetFlagsGen(); SpecTypeFlags GenFlags(); void DumpConfig(const SpectrumConfig &cfg); bool TestSetGet(Spectrum &s); const std::string &ProtoName(int proto); const std::string &ProtoName(const SpecTypeFlags &flags); public: SpectrumTest() : confidx(0) {}; bool Do(); bool TestConstruction(); bool TestConfiguration(); bool TestInstantiationAndGetSet(); bool TestSynchronization(); bool TestScales(); bool TestCopies(); const std::string &Why() {return reason;} bool TestXML(); }; void SpectrumTest::ResetConfGen() {confidx = protoidx = 0;} void SpectrumTest::ResetFlagsGen() {protoidx = 0;} const std::string &SpectrumTest::ProtoName(int proto) { static std::string str; str=""; for (int i=0; i<4; i++) if (proto&(1< array(size); array.SetSize(size); for (i=0; i array(size); array.SetSize(size); for (i=0; i array; array.Resize(size); array.SetSize(size); for (i=0; i array; array.Resize(size); array.SetSize(size); for (i=0; i #include //rand() #include "SpectrumAdder.hxx" #include "SpectrumComp.hxx" #include "OctaveVector.hxx" using CLAM::SpectrumAdder; using CLAM::SpecAdderConfig; using CLAM::Err; namespace CLAMTest { // Loads the vectors from a file, if they have not been previously loaded, // and sets the arguments to the loaded values. bool SetTestVectors(Spectrum &s1, Spectrum &s2, Spectrum &s3) { bool remove1=false,remove2=false,remove3=false; static bool loaded=false; static Spectrum orig1,orig2,orig3; if (!loaded) { std::ifstream file("SpectrumAdder2Test.data"); SpecTypeFlags f; f.bMagPhase=false; f.bComplex=true; orig1.SetSize(1024); orig2.SetSize(1024); orig3.SetSize(1024); orig1.SetType(f); orig2.SetType(f); orig3.SetType(f); if (file) { std::cerr << "Loading Input1..." << std::endl; if (!CLAMTest::LoadOctaveComplexVector(file,"Input1",orig1.GetComplexArray())) { std::cerr << "Could not find Input1 vector in input!" << std::endl; return false; } std::cerr << "Loading Input2..." << std::endl; if (!CLAMTest::LoadOctaveComplexVector(file,"Input2",orig2.GetComplexArray())) { std::cerr << "Could not find Audio vector in input!" << std::endl; return false; } std::cerr << "Loading Output..." << std::endl; if (!CLAMTest::LoadOctaveComplexVector(file,"Output",orig3.GetComplexArray())) { std::cerr << "Could not find Audio vector in input!" << std::endl; return false; } file.close(); } else { std::cerr << "Generating Inputs and output..." << std::endl; for (int i = 0; i < 1024; i++) { orig1.GetComplexArray().GetPtr()[i] = Complex(10.0*(TData)rand()/(TData)RAND_MAX, 10.0*(TData)rand()/(TData)RAND_MAX); orig2.GetComplexArray().GetPtr()[i] = Complex(10.0*(TData)rand()/(TData)RAND_MAX, 10.0*(TData)rand()/(TData)RAND_MAX); orig3.GetComplexArray().GetPtr()[i] = orig1.GetComplexArray().GetPtr()[i] + orig2.GetComplexArray().GetPtr()[i]; } } loaded=true; } SpecTypeFlags spec; s1.GetType(spec); if (!spec.bComplex) { spec.bComplex=1; s1.SetType(spec); remove1=true; } s2.GetType(spec); if (!spec.bComplex) { spec.bComplex=1; s2.SetType(spec); remove2=true; } s3.GetType(spec); if (!spec.bComplex) { spec.bComplex=1; s3.SetType(spec); remove3=true; } s1.SetComplexArray(orig1.GetComplexArray()); s2.SetComplexArray(orig2.GetComplexArray()); s3.SetComplexArray(orig3.GetComplexArray()); spec.bMagPhase=spec.bPolar=spec.bMagPhaseBPF=false; s1.SynchronizeTo(spec); s2.SynchronizeTo(spec); s3.SynchronizeTo(spec); if (remove1) { s1.GetType(spec); spec.bComplex=false; s1.SetType(spec); } if (remove2) { s2.GetType(spec); spec.bComplex=false; s2.SetType(spec); } if (remove3) { s3.GetType(spec); spec.bComplex=false; s3.SetType(spec); } return true; } void SetPrototypes(int proto, Spectrum &s) { SpecTypeFlags f; f.bComplex=proto&(1<<(int)SpecTypeFlags::eComplex); f.bPolar=proto&(1<<(int)SpecTypeFlags::ePolar); f.bMagPhase=proto&(1<<(int)SpecTypeFlags::eMagPhase); f.bMagPhaseBPF=proto&(1<<(int)SpecTypeFlags::eMagPhaseBPF); s.SetType(f); } bool TestAdder1(SpectrumAdder &adder) { return true; } bool TestAdder2(SpectrumAdder &adder) { Spectrum in1,in2,out,out_good; Spectrum *inputs[2] = { &in1, &in2 }; int proto1,proto2,proto3; TData max_err = 0.00001; SpecAdderConfig cfg; cfg.SetNInputs(2); if (adder.IsRunning()) adder.Stop(); adder.Configure(cfg); adder.Start(); in1.SetSize(1024); in2.SetSize(1024); out.SetSize(1024); out_good.SetSize(1024); for (proto1=1; proto1<16; proto1++) for (proto2=1; proto2<16; proto2++) for (proto3=1; proto3<16; proto3++) { if (proto1 == 8 | proto2 == 8 | proto3 == 8) { std::cerr << "skipped "; continue; } SetPrototypes(proto1,in1); SetPrototypes(proto2,in2); SetPrototypes(proto3,out); SetTestVectors(in1,in2,out_good); adder.SetPrototypes(inputs,out); adder.Do(inputs,out); TData diff = CLAMTest::TestUtils::MaxDiff(out,out_good); std::cerr << diff << ' '; if (diff > max_err) return false; std::cerr.flush(); } return true; } bool TestAdder3(SpectrumAdder &adder) { return true; } } int main() { try { bool res; CLAM::SpectrumAdder adder; std::cerr << "Trying 1 input" << std::endl; res = CLAMTest::TestAdder1(adder); if (res) std::cerr << std::endl << "Passed." << std::endl; else { std::cerr << std::endl << "Failed." << std::endl; return 1; } std::cerr << "Trying 2 inputs" << std::endl; res = CLAMTest::TestAdder2(adder); if (res) std::cerr << std::endl << "Passed." << std::endl; else { std::cerr << std::endl << "Failed." << std::endl; return 1; } std::cerr << "Trying 3 inputs" << std::endl; res = CLAMTest::TestAdder3(adder); if (res) std::cerr << std::endl << "Passed." << std::endl; else { std::cerr << std::endl << "Failed." << std::endl; return 1; } } catch (CLAM::Err e) { e.Print(); } } clam-1.4.0/test/NonPortedTests/SConstruct0000644000000000000000000001347211222151672017100 0ustar rootroot#!/usr/bin/python import os import glob import sys options = Variables('options.cache', ARGUMENTS) options.Add(PathVariable('prefix', 'The prefix where the application will be installed', '')) options.Add(PathVariable('clam_prefix', 'The prefix where CLAM was installed', '')) options.Add(BoolVariable('release', 'Enabling compiler optimizations', 'no') ) options.Add(BoolVariable('verbose', 'Display the full command line instead a short command description', 'no') ) options.Add(PathVariable('external_dll_path', '(Windows only) The place where the NSIS packager takes the installed DLL from', '.')) if sys.platform=="linux2" : options.Add(BoolVariable('crossmingw', 'Using MinGW crosscompiler mode', 'no') ) def scanFiles(pattern, paths) : files = [] for path in paths : files+=glob.glob(os.path.join(path,pattern)) return files def recursiveDirs(root) : return filter( (lambda a : a.rfind( ".svn")==-1 ), [ a[0] for a in os.walk(root)] ) def unique(list) : return dict.fromkeys(list).keys() toolchain='default' if sys.platform == 'win32': toolchain = 'mingw' env = Environment(ENV=os.environ, tools=[toolchain], options=options) options.Save('options.cache', env) Help(options.GenerateHelpText(env)) env.SConsignFile() # Single signature file crosscompiling = env.has_key("crossmingw") and env["crossmingw"] isWindowsPlatform = sys.platform=='win32' or crosscompiling isLinuxPlatform = sys.platform=='linux2' and not crosscompiling isDarwinPlatform = sys.platform=='darwin' CLAMInstallDir = env['clam_prefix'] clam_sconstoolspath = os.path.join(CLAMInstallDir,'share','clam','sconstools') env.Tool('clam', toolpath=[clam_sconstoolspath]) env.Tool('nsis', toolpath=[clam_sconstoolspath]) if sys.platform=='darwin' : env.Tool('bundle', toolpath=[clam_sconstoolspath]) env.Tool('dmg', toolpath=[clam_sconstoolspath]) if crosscompiling : env.Tool('crossmingw', toolpath=[clam_sconstoolspath]) sys.path.append(clam_sconstoolspath) env['CXXFILESUFFIX'] = '.cxx' if not env['verbose']: env['CXXCOMSTR'] = '== Compiling $SOURCE' env['SHCXXCOMSTR'] = '== Compiling shared $SOURCE' env['LINKCOMSTR'] = '== Linking $TARGET' env['SHLINKCOMSTR'] = '== Linking library $TARGET' env.EnableClamModules([ 'clam_core', 'clam_audioio', 'clam_processing', ], CLAMInstallDir) mainSources = { 'Chordata' : os.path.join('src','main.cxx'), } sourcePaths = [ os.path.join('.'), ] extraPaths = [] extraPaths += [ CLAMInstallDir+'/include', CLAMInstallDir+'/include/CLAM', # KLUDGE to keep old style includes "../UnitTests/CommonHelpers/", ] includePaths = sourcePaths + extraPaths sources = scanFiles('*.cxx', sourcePaths) sources = unique(sources) env.Append(CPPPATH=includePaths) #env.Prepend(LIBS="clam_vmqt4") if sys.platform=='darwin' : env.Append(CPPFLAGS='-DRESOURCES_BASE="\\"Chordata.app/Contents/Resources\\""') else : env.Append(CPPFLAGS='-DRESOURCES_BASE="\\"' + env['prefix'] + '/share/chordata\\""') if sys.platform!='win32' : # TODO: This should not be hardcoded neither prefix (because package intall) env.Append(CPPFLAGS='-DDATA_EXAMPLES_PATH="\\"%s\\""'%env['prefix'] + '/share/chordata/example-data') if sys.platform=='linux2' : if env['release'] : env.Append( CCFLAGS=['-g','-O3','-fomit-frame-pointer','-Wall'] ) else : env.Append( CCFLAGS=['-g','-O3','-Wall'] ) #commonObjects = env.StaticLibrary(target="chordata", source=sources) programs = [ env.Program(source = source) for source in sources] example_data = [ #'example-data/Chords.pro' ] pluginDefines=['-DQT_PLUGIN','-DQT_NO_DEBUG','-DQDESIGNER_EXPORT_WIDGETS','-D_REENTRANT'] env.AppendUnique(CPPFLAGS=pluginDefines) env.AppendUnique(LIBS='cppunit') def absolutePosixPathToWine(dir) : return 'z:'+'\\\\'.join(dir.split('/')) if isWindowsPlatform : winqtdir=env['QTDIR'] if crosscompiling : env['NSIS_MAKENSIS'] = 'wine ~/.wine/dosdevices/c:/Program\ Files/NSIS/makensis' if crosscompiling : winqtdir = absolutePosixPathToWine(winqtdir) externalDllPath = env['external_dll_path'] if crosscompiling : externalDllPath = absolutePosixPathToWine(externalDllPath) winclampath = CLAMInstallDir if crosscompiling : winclampath = absolutePosixPathToWine(winclampath) if crosscompiling : env.AddPostAction(programs, env.Action(["i586-mingw32msvc-strip $TARGET"])) installTargets += [ env.Install( env['prefix']+"/bin", os.path.join(env['QTDIR'],'bin',"Qt"+dll+"4.dll") ) for dll in 'Core', 'Gui', 'OpenGL'] env.Append(NSIS_OPTIONS=['/DVERSION=%s' % fullVersion ]) env.Append(NSIS_OPTIONS=['/DQTDIR=%s'%winqtdir ]) env.Append(NSIS_OPTIONS=['/DEXTERNALDLLDIR=%s' % externalDllPath ]) env.Append(NSIS_OPTIONS=['/DCLAMINSTALLDIR=%s' % winclampath ]) # Get the visual studio runtimes path for vcRuntimeDir in os.environ['PATH'].split(";") : vcRuntimeDir = os.path.normpath(vcRuntimeDir) if os.access(os.path.join(vcRuntimeDir,"msvcr71.dll"),os.R_OK) : break env.Append(NSIS_OPTIONS=['/DVCRUNTIMEDIR=%s' % vcRuntimeDir ]) win_packages = [env.Nsis( source='resources/installer.nsi')] env.Alias('package', win_packages) if sys.platform=='darwin' : # TODO: Review why those flags were added# TODO: Review why those flags were added# TODO: Review why those flags were added env.Append(CPPFLAGS='-DRESOURCES_BASE="\\"Chordata.app/Contents/Resources\\""') env.AppendUnique( LINKFLAGS=['-dynamic','-bind_at_load']) #TODO install resources installTargets = [] mac_bundle = env.Bundle( BUNDLE_NAME='Chordata', BUNDLE_BINARIES=programs, # BUNDLE_RESOURCEDIRS=['foo','bar'], BUNDLE_PLIST='resources/Info.plist', BUNDLE_ICON='resources/CLAM-Chordata.icns', ) env.Alias('bundle', mac_bundle) #TODO mac_bundle should be dependency of Dmga: arch = os.popen("uname -p").read().strip() mac_packages = env.Dmg('CLAM_Chordata-%s-%s.dmg'% (fullVersion, arch), [ env.Dir('Chordata.app/'), env.Dir('example-data/'), ]+installTargets ) env.Alias('package', mac_packages) env.Default(programs) clam-1.4.0/test/NonPortedTests/TestArray.cxx0000644000000000000000000003126111076377340017515 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "Array.hxx" #include "Complex.hxx" #include "Component.hxx" #include "DynamicType.hxx" #include "XMLAdapter.hxx" #include #include #include #include using namespace CLAM; static int result = 0; class SelfRefering { int data; SelfRefering *me; public: // Default constructor: initializes self-reference. int Data() const {return data;} void Data(int i) {data=i;} SelfRefering(int i=0) { data = i; me = this; } // Copy constructor: must be implemented to keep the self-reference consistent. SelfRefering(const SelfRefering& src) { data=src.data; me = this; } // Copy operator: same as for the constructor. SelfRefering &operator = (const SelfRefering& src) { data=src.data; me = this; return *this; } // The destructor: is everything ok? ~SelfRefering() { if (me != this) throw(CLAM::Err("SelfRefering error: invalid self reference")); } bool operator ==(const SelfRefering& src) const { return Data() == src.Data(); } bool operator !=(const SelfRefering& src) const { return Data() != src.Data(); } }; class A : public CLAM::Component { public: int a; float b; double c; void f() {}; A() : a(8), b(8), c(8) { std::cout << "Constructiong A at : " << this << std::endl; } A(const A& arg) : a(arg.a), b(arg.b), c(arg.c) { std::cout << "Constructiong A by copy at "<< this <<" from argument at : " << &arg << std::endl; } ~A() { std::cout << "Destroying A...... at : "<< this << std::endl; } const char * GetClassName() const {return "A";} void LoadFrom (CLAM::Storage & store) { } void StoreOn(CLAM::Storage & storage) const { XMLAdapter adaptera(a, "Aa", true); XMLAdapter adapterb(b, "Ab", true); XMLAdapter adapterc(c, "Ac", true); storage.Store(adaptera); storage.Store(adapterb); storage.Store(adapterc); } }; class B : public CLAM::Component { public: int a; float b; double c; void f() {}; virtual ~B() { std::cout << "Destroying B (virtual dest)...... at : "<< this << std::endl; } B (const B& arg) : a(arg.a), b(arg.b), c(arg.c) { std::cout << "Constructiong B by copy at "<< this <<" from argument at : " << &arg << std::endl; } B() : a(9), b(9), c(9) { std::cout << "Constructiong B at : " << this << std::endl; } const char * GetClassName() const {return "A";} void LoadFrom (CLAM::Storage & store) { } void StoreOn(CLAM::Storage & storage) const { XMLAdapter adaptera(a, "Ba", true); XMLAdapter adapterb(b, "Bb", true); XMLAdapter adapterc(c, "Bc", true); storage.Store(adaptera); storage.Store(adapterb); storage.Store(adapterc); } }; class Dyn : public DynamicType { public: DYNAMIC_TYPE(Dyn, 3); DYN_ATTRIBUTE(0, public, Array, IntegerList); DYN_ATTRIBUTE(1, public, A, MyA); DYN_ATTRIBUTE(2, public, Array, MyBList ); virtual ~Dyn() { std::cout << "Deleting a Dyn at : " << this << std::endl; } }; std::istream &operator>>(std::istream &in, SelfRefering &d) { unsigned int i; in >> i; d.Data(i); return in; } std::ostream &operator<<(std::ostream &out, const SelfRefering &d) { out << d.Data(); return out; } struct tA { int data[100]; }; struct tB { int data[100]; }; std::istream &operator>>(std::istream &in, tA &d) { in >> d.data[0]; return in; } std::istream &operator>>(std::istream &in, tB &d) { in >> d.data[0]; return in; } std::ostream &operator<<(std::ostream &out, const tA &d) { out << d.data[0]; return out; } std::ostream &operator<<(std::ostream &out, const tB &d) { out << d.data[0]; return out; } namespace CLAM { // template<> Array& Array::operator = (const Array& src) // { // mStep = src.mStep; // Resize(src.Size()); // SetSize(src.Size()); // memcpy(mpData,src.mpData,sizeof(B)*src.mSize); // return *this; // } } // Let's see how tough is this guy... void hardcore_test() { std::cout << "'Evil' Test on the CLAM::Array" << std::endl; time( NULL ); // Initializing the seeds for getting true random numbers Array< int > mySimpleIntArray; Array< Complex > myComplexArray; //:) Array< B > myArrayOfComponents; Array< Dyn > myDynamicTypeArray; // arrays initialization unsigned int index; std::cout << "'Evil' AddElem Test starting:" << std::endl; for ( index = 0; index < 30; index++ ) { Dyn myDyn; try { mySimpleIntArray.AddElem( index ); myComplexArray.AddElem( Complex( float(index), float(index) ) ); myArrayOfComponents.AddElem( B() ); // The inicialization of the Dynamic Type Array will be quite special if ( ( float ( rand() ) / float( RAND_MAX ) ) > 0.5f ) { myDyn.AddIntegerList(); myDyn.UpdateData(); myDyn.SetIntegerList( mySimpleIntArray ); } if ( ( float ( rand() ) / float( RAND_MAX ) ) > 0.5f ) { myDyn.AddMyA(); myDyn.UpdateData(); myDyn.SetMyA( A() ); } if ( ( float ( rand() ) / float( RAND_MAX ) ) > 0.5f ) { myDyn.AddMyBList(); myDyn.UpdateData(); myDyn.SetMyBList( myArrayOfComponents ); } myDynamicTypeArray.AddElem( myDyn ); std::cout << "." << std::endl; } catch ( CLAM::Err e ) { std::cout << " F(" << index << ") : " << e.what() << std::endl; result = 1; } } std::cout << "'Evil' AddElem test done" << std::endl; // 'Evil' DeleteElem test unsigned int chosen=0; std::cout << "'Evil' DeleteElem test starting" << std::endl; for ( index = 0; index < 15; index++ ) { try { chosen = int( ( float ( rand() ) / float( RAND_MAX ) ) * float(mySimpleIntArray.Size()-1) ); mySimpleIntArray.DeleteElem( chosen ); std::cout << "I(" << chosen << ")S "; chosen = int( ( float ( rand() ) / float( RAND_MAX ) ) * float(myComplexArray.Size()-1) ); myComplexArray.DeleteElem( chosen ); std::cout << "C(" << chosen << ")S "; chosen = int( ( float ( rand() ) / float( RAND_MAX ) ) * float(myArrayOfComponents.Size()-1) ); myArrayOfComponents.DeleteElem( chosen ); std::cout << "Co(" << chosen << ")S "; chosen = int( ( float ( rand() ) / float( RAND_MAX ) ) * float(myDynamicTypeArray.Size()-1) ); myDynamicTypeArray.DeleteElem( chosen ); std::cout << "DT(" << chosen << ")S "; } catch( CLAM::Err e ) { std::cout << "F(" << chosen << ") "; } std::cout << std::endl; } std::cout << "'Evil' DeleteElem test done" << std::endl; } int main() { using namespace CLAM; std::cout << "Legend:" << std::endl << " \".\" : passed check" << std::endl << " \"X\" : failed check" << std::endl << " \"S\" : failed self reference consistency check" << std::endl; try { { // We build all the local variables in a new code block, // So they get destroyed inside the try/catch block. int i; // Array construction std::cout << "Testing construction" << std::endl; Array intarray; Array doublearray; Array > complexarray; Array selfarray; // Element addition: // We build 25 ... 49 std::cout << "Testing element adition"; for (i=25; i<50; i++) { intarray.AddElem(i); doublearray.AddElem(TData(i)); complexarray.AddElem(ComplexTmpl(i,i)); selfarray.AddElem(SelfRefering(i)); std::cout << '.' << std::flush; } // Element Insertion: // We get 0...39 25 ... 49 std::cout << std::endl << "Testing element insertion"; for (i=0; i<40; i++) { intarray.InsertElem(i,i); doublearray.InsertElem(i,TData(i)); complexarray.InsertElem(i,ComplexTmpl(i,i)); selfarray.InsertElem(i,SelfRefering(i)); std::cout << '.' << std::flush; } // Array resizing int oldsize; std::cout << std::endl << "Testing array resizing"; oldsize = intarray.AllocatedSize(); for (i=oldsize; i(i,i) ) { std::cout << intarray[i] << 'X'; result = 1; } else std::cout << '.'; } std::cout << std::endl << "Testing asignment and comparision"; Array newint(intarray); if (! (newint == intarray) ) { std::cout << "X"; result = 1; } else std::cout << "."; newint = intarray; if (! (newint == intarray) ) { std::cout << "X"; result = 1; } else std::cout << "."; Array newdouble(doublearray); if (! (newdouble == doublearray) ) { std::cout << "X"; result = 1; } else std::cout << "."; newdouble = doublearray; if (! (newdouble == doublearray) ) { std::cout << "X"; result = 1; } else std::cout << "."; Array > newcomplex(complexarray); if (! (newcomplex == complexarray) ) { std::cout << "X"; result = 1; } else std::cout << "."; newcomplex = complexarray; if (! (newcomplex == complexarray) ) { std::cout << "X"; result = 1; } else std::cout << "."; Array newself(selfarray); if (! (newself == selfarray) ) { std::cout << "X"; result = 1; } else std::cout << "."; newself = selfarray; if (! (newself == selfarray) ){ std::cout << "X"; result = 1; } else std::cout << "."; //Concatenation std::cout << std::endl << "Testing concatenation"; oldsize=newint.Size(); newint += intarray; for (i=0; i obj1, obj2; long j; for (j=0; j<10000000; j++) obj1=obj2; std::cout << " done" << std::endl;; std::cout << " Optimised copy ..."; Array obj3, obj4; for (j=0; j<10000000; j++) obj3=obj4; std::cout << " done" << std::endl;; } // Array destruction :) // hardcore test hardcore_test(); if (result) { std::cout << "Failed." << std::endl; return result; } std::cout << "Passed." << std::endl; return 0; } catch(CLAM::Err e) { e.Print(); return 1; } } clam-1.4.0/test/NonPortedTests/SpectrumComp.hxx0000644000000000000000000001323210610720021020200 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "Spectrum.hxx" #include "SpectrumConfig.hxx" #include namespace CLAMTest { using namespace CLAM; namespace TestUtils { /** Spectrum comparison */ TData CompareMagPhase(Spectrum &s1, Spectrum &s2); TData CompareComplex(Spectrum &s1, Spectrum &s2); TData ComparePolar(Spectrum &s1, Spectrum &s2); TData CompareBPF(Spectrum &s1, Spectrum &s2); /** Returns the maximun of the magnitudes of the complex * differences for each point */ TData MaxDiff(Spectrum &s1, Spectrum &s2) { SpecTypeFlags f1,f2; if (s1.GetSize() != s2.GetSize()) throw(Err("MaxDif: Comparing spectrums of different size")); if (s1.GetSpectralRange() != s2.GetSpectralRange()) throw(Err("MaxDif: Comparing spectrums of different spectral range")); s1.GetType(f1); s2.GetType(f2); // Check if comparision with no conversion is possible. if (f1.bComplex && f2.bComplex) return CompareComplex(s1,s2); if (f1.bMagPhase && f2.bMagPhase) return CompareMagPhase(s1,s2); if (f1.bPolar && f2.bPolar) return ComparePolar(s1,s2); if (f1.bMagPhaseBPF && f2.bMagPhaseBPF) return CompareBPF(s1,s2); // We need to convert. if (f1.bComplex || f2.bComplex) return CompareComplex(s1,s2); if (f1.bMagPhase || f2.bMagPhase) return CompareMagPhase(s1,s2); if (f1.bPolar || f2.bPolar) return ComparePolar(s1,s2); if (f1.bMagPhaseBPF || f2.bMagPhaseBPF) return CompareBPF(s1,s2); throw(Err("SpectrumCompare: No attributes in inputs.")); } TData CompareComplex(Spectrum &s1, Spectrum &s2) { Complex *c1,*c2; TData max_dif=0.0; int i,size = s1.GetSize(); bool remove1=false,remove2=false; SpecTypeFlags flags; s1.GetType(flags); if (!flags.bComplex) { remove1=true; flags.bComplex=true; s1.SetTypeSynchronize(flags); } s2.GetType(flags); if (!flags.bComplex) { remove2=true; flags.bComplex=true; s2.SetTypeSynchronize(flags); } c1 = s1.GetComplexArray().GetPtr(); c2 = s2.GetComplexArray().GetPtr(); if (!c1 || !c2) throw(Err("CompareMagPhase: Null complex array in spectrum.")); for (i=0; i max_dif) max_dif=diff; } if (remove1) { s1.GetType(flags); flags.bComplex=false; s1.SetType(flags); } if (remove2) { s2.GetType(flags); flags.bComplex=false; s2.SetType(flags); } return max_dif; } TData CompareMagPhase(Spectrum &s1, Spectrum &s2) { TData *m1,*m2,*p1,*p2; TData max_dif=0.0; int i,size = s1.GetSize(); bool remove1=false,remove2=false; SpecTypeFlags flags; s1.GetType(flags); if (!flags.bMagPhase) { remove1=true; flags.bMagPhase=true; s1.SetTypeSynchronize(flags); } s2.GetType(flags); if (!flags.bMagPhase) { remove2=true; flags.bMagPhase=true; s2.SetTypeSynchronize(flags); } m1 = s1.GetMagBuffer().GetPtr(); m2 = s2.GetMagBuffer().GetPtr(); p1 = s1.GetPhaseBuffer().GetPtr(); p2 = s2.GetPhaseBuffer().GetPtr(); if (!m1 || !m2 || !p1 || !p2) throw(Err("CompareMagPhase: Null buffer in spectrum Mag or Phase.")); for (i=0; i max_dif) max_dif=diff; } if (remove1) { s1.GetType(flags); flags.bMagPhase=false; s1.SetType(flags); } if (remove2) { s2.GetType(flags); flags.bMagPhase=false; s2.SetType(flags); } return max_dif; } TData ComparePolar(Spectrum &s1, Spectrum &s2) { Polar *p1,*p2; TData max_dif=0.0; int i,size = s1.GetSize(); bool remove1=false,remove2=false; SpecTypeFlags flags; s1.GetType(flags); if (!flags.bPolar) { remove1=true; flags.bPolar=true; s1.SetTypeSynchronize(flags); } s2.GetType(flags); if (!flags.bPolar) { remove2=true; flags.bPolar=true; s2.SetTypeSynchronize(flags); } p1 = s1.GetPolarArray().GetPtr(); p2 = s2.GetPolarArray().GetPtr(); if (!p1 || !p2) throw(Err("ComparePolar: Null Polar array in spectrum")); for (i=0; i max_dif) max_dif=diff; } if (remove1) { s1.GetType(flags); flags.bPolar=false; s1.SetType(flags); } if (remove2) { s2.GetType(flags); flags.bPolar=false; s2.SetType(flags); } return max_dif; } TData CompareBPF(Spectrum &s1, Spectrum &s2) { throw(Err("CompareBPF: Not implemented")); } } } clam-1.4.0/test/FunctionalTests/0000755000000000000000000000000011344231441015227 5ustar rootrootclam-1.4.0/test/FunctionalTests/SConscript0000644000000000000000000000340511160750656017255 0ustar rootroot#!/usr/bin/python Import('env') import sys, os, glob def scanFiles(pattern, paths) : files = [] for path in paths : files+=glob.glob(os.path.join(path,pattern)) return files def recursiveDirs(root) : return filter( (lambda a : a.rfind( ".svn")==-1 ), [ a[0] for a in os.walk(root)] ) def unique(list) : return dict.fromkeys(list).keys() folders = [ os.path.join('..','UnitTests'), os.path.join('..','UnitTests','CommonHelpers'), os.path.join('CommonHelpers'), os.path.join('FlowControlTests'), os.path.join('ProcessingTests'), # os.path.join('Applications','MIRTests'), ] blacklist = [ os.path.join('..','UnitTests','TestRunnerQt.cxx'), os.path.join('ProcessingTests','TestMIDIIO.cxx'), os.path.join('ProcessingTests','TestOnsetDetector.cxx'), os.path.join('ProcessingTests','TestSpectralPeakDetect.cxx'), os.path.join('ProcessingTests','TestSMSAnalysis.cxx'), ] if 'crossmingw' in env['TOOLS'] or 'mingw' in env['TOOLS']: blacklist += [ # use exceptions not supported by hardy mingw (they use sjlj) os.path.join('ProcessingTests','TestControlTraces.cxx'), os.path.join('ProcessingTests','TestMultiChannelAudioFileReader.cxx'), os.path.join('ProcessingTests','TestMultiChannelAudioFileWriter.cxx'), ] #folders = [ os.path.join('..','..','..','test', folder) for folder in folders ] #blacklist = [ os.path.join('..','..','..','test', blacksheep) for blacksheep in blacklist ] sources = scanFiles('*.cxx', folders) headers = scanFiles('*.hxx', folders) for blacksheep in blacklist : sources.remove(blacksheep) if sys.platform != 'win32' : env.Append( CPPPATH=['include'] ) functional_tests = env.Program( 'FunctionalTests', sources ) test_alias = Alias( 'run_functional_tests', [functional_tests], functional_tests[0].abspath ) AlwaysBuild( test_alias ) clam-1.4.0/test/FunctionalTests/CommonHelpers/0000755000000000000000000000000011344231441020002 5ustar rootrootclam-1.4.0/test/FunctionalTests/CommonHelpers/AudioCollator.hxx0000644000000000000000000001074511016524554023311 0ustar rootroot#ifndef AudioCollator_hxx #define AudioCollator_hxx #include #include "cppUnitHelper.hxx" #include #include #include #include #include #include #include // used for open(..) : we want to check if some file exists namespace CLAMTest { /// checks that a given filename exists inline bool helperFileExist(const std::string& filename) { std::fstream file; file.open( filename.c_str() ); return file.is_open(); } /// Loads audio from file using processing AudioFileIn inline void helperLoadAudioFromFile(const std::string filename, CLAM::Audio& audioToWrite ) { CLAM_ASSERT( helperFileExist(filename), "helperLoadAudioFromFile(..) received a non existing file" ); CLAM::MonoAudioFileReaderConfig conf; conf.SetSourceFile(filename); CLAM::MonoAudioFileReader in(conf); in.Start(); audioToWrite.SetSize( in.GetHeader().GetSamples() ); in.Do( audioToWrite ); in.Stop(); } /// Saves audio to file using processig AudioFileOut inline void helperSaveAudioToFile( CLAM::Audio& audio, const std::string filename ) { CLAM::MonoAudioFileWriterConfig cfg; cfg.SetTargetFile(filename); cfg.SetSampleRate(audio.GetSampleRate()); CLAM::MonoAudioFileWriter writer(cfg); writer.Start(); writer.Do(audio); writer.Stop(); } /// this helper func. should result in the future in a processing or assert. inline bool helperAudiosAreEqual( CLAM::Audio& first, CLAM::Audio& second, std::string& whyDifferents, double delta = 0.001) { if (first.GetSize() != second.GetSize() ) { std::stringstream formatter; formatter << "different audio sizes: first " << first.GetSize() << " second " << second.GetSize() << std::endl; whyDifferents += formatter.str(); return false; } if (first.GetSampleRate() != second.GetSampleRate() ) { std::stringstream formatter; formatter << "compared audios have different sample-rates: first "<< first.GetSampleRate() << " second " << second.GetSampleRate() << std::endl; whyDifferents += formatter.str(); } CLAM::DataArray& samplesFirst = first.GetBuffer(); CLAM::DataArray& samplesSecond = second.GetBuffer(); for (int i=0; i delta ) { std::stringstream formatter; formatter << "found a different sampler in position " << i << " first value is "<< samplesFirst[i] << " second value is " << samplesSecond[i] << " with delta = " << delta; whyDifferents += formatter.str(); return false; } } return true; } /// shorthand for loading an audio and then call /// helperAudiosAreEqual /// in case of not-equals, saves the result audio file inline bool helperAudioIsEqualToAudioFile( CLAM::Audio& audio, const std::string& audioFile, std::string& whyDifferents, double delta=0.0001 ) { std::string resultAudioFile = audioFile+"_result.wav"; whyDifferents = "comparing with file: "+ audioFile + "\nThe calculated audio has been saved in: " + resultAudioFile +"\n"; if( !helperFileExist(audioFile) ) { helperSaveAudioToFile(audio, resultAudioFile); return false; } CLAM::Audio loadedAudio; helperLoadAudioFromFile( audioFile, loadedAudio); bool result = helperAudiosAreEqual(audio, loadedAudio, whyDifferents, delta); if (!result) { helperSaveAudioToFile(audio, resultAudioFile); } return result; } /// shorthand for loading two audios and then call /// helperAudiosAreEqual /// in any case it does NOT save any file (no need to) inline bool helperCompareTwoAudioFiles( const std::string& audioFile1, const std::string& audioFile2, std::string& whyDifferents, double delta=0.0001 ) { if( !helperFileExist(audioFile1) ) { whyDifferents += "Error in helperCompareTwoAudioFiles: file "+audioFile1+" doesn't exist"; return false; } if (!helperFileExist(audioFile2) ) { whyDifferents += "Error in helperCompareTwoAudioFiles: file "+audioFile2+" doesn't exist"; return false; } whyDifferents += "comparing file1: " + audioFile1 + " with file2: "+audioFile2 + "\n"; CLAM::Audio loadedAudio1, loadedAudio2; helperLoadAudioFromFile( audioFile1, loadedAudio1); helperLoadAudioFromFile( audioFile2, loadedAudio2); bool result = helperAudiosAreEqual(loadedAudio1, loadedAudio2, whyDifferents, delta); return result; } } // namespace CLAMTest #endif clam-1.4.0/test/FunctionalTests/ProcessingTests/0000755000000000000000000000000011344231441020366 5ustar rootrootclam-1.4.0/test/FunctionalTests/ProcessingTests/TestFFT.cxx0000644000000000000000000002172510636000220022370 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "similarityHelper.hxx" #include "FFT_base.hxx" #include "Audio.hxx" #include "Spectrum.hxx" #include "XMLStorage.hxx" #include "ProcessingFactory.hxx" namespace CLAMTest { class FFTFunctionalTest : public CppUnit::TestFixture { protected: static double smEqualityThreshold; static bool smBack2BackDataLoaded; static CLAM::Spectrum smReferenceP2Spectrum; static CLAM::Spectrum smReferenceNP2Spectrum; std::string mPathToTestData; CLAM::FFT_base * mProcessing; virtual const std::string getProcessing()=0; void setupSine_F0400Hz_SR8kHz( CLAM::Audio& audio, int nSamples ) { const CLAM::TSize sampleRate = 8000; const CLAM::TData sineFreq = 400.0f; audio.SetSize( nSamples ); audio.SetSampleRate( sampleRate ); audio.SetBeginTime( CLAM::TTime(0.0) ); for ( CLAM::TSize i=0; iConfigure( processingConfig ); mProcessing->Start(); mProcessing->Do( input, output ); mProcessing->Stop(); double similarity = evaluateSimilarity( smReferenceP2Spectrum.GetMagBuffer(), output.GetMagBuffer() ); CPPUNIT_ASSERT( smEqualityThreshold <= similarity ); CPPUNIT_ASSERT( smReferenceP2Spectrum.GetSpectralRange() == output.GetSpectralRange() ); } void test_WithComplex() { CLAM::Audio input; CLAM::SpecTypeFlags flg; flg.bMagPhase=0; flg.bComplex=1; CLAM::Spectrum output; output.SetType(flg); CLAM::FFTConfig processingConfig; setupSine_F0400Hz_SR8kHz_1024samples( input ); output.SetSize( CLAM::TSize(input.GetSize()/2 + 1) ); processingConfig.SetAudioSize( input.GetSize() ); mProcessing->Configure( processingConfig ); mProcessing->Start(); mProcessing->Do(input,output); mProcessing->Stop(); flg.bMagPhase=1; output.SetTypeSynchronize(flg); double similarity = evaluateSimilarity( smReferenceP2Spectrum.GetMagBuffer(), output.GetMagBuffer() ); CPPUNIT_ASSERT( smEqualityThreshold <= similarity ); CPPUNIT_ASSERT( smReferenceP2Spectrum.GetSpectralRange() == output.GetSpectralRange() ); } void test_WithBPF() { CLAM::Audio input; CLAM::SpecTypeFlags flg; flg.bMagPhase=0; flg.bMagPhaseBPF=1; CLAM::Spectrum output; output.SetType(flg); CLAM::FFTConfig processingConfig; setupSine_F0400Hz_SR8kHz_1024samples( input ); output.SetSize( CLAM::TSize(input.GetSize()/2 + 1) ); processingConfig.SetAudioSize( input.GetSize() ); mProcessing->Configure( processingConfig ); mProcessing->Start(); mProcessing->Do(input,output); mProcessing->Stop(); flg.bMagPhase=1; output.SetTypeSynchronize(flg); double similarity = evaluateSimilarity( smReferenceP2Spectrum.GetMagBuffer(), output.GetMagBuffer() ); CPPUNIT_ASSERT( smReferenceP2Spectrum.GetSpectralRange() == output.GetSpectralRange() ); CPPUNIT_ASSERT( smReferenceP2Spectrum.GetSize() == output.GetSize() ); CPPUNIT_ASSERT( smEqualityThreshold <= similarity ); } void test_WithPolar() { CLAM::Audio input; CLAM::SpecTypeFlags flg; flg.bMagPhase=0; flg.bPolar=1; CLAM::Spectrum output; output.SetType(flg); CLAM::FFTConfig processingConfig; setupSine_F0400Hz_SR8kHz_1024samples( input ); output.SetSize( CLAM::TSize(input.GetSize()/2 + 1) ); processingConfig.SetAudioSize( input.GetSize() ); mProcessing->Configure( processingConfig ); mProcessing->Start(); mProcessing->Do(input,output); mProcessing->Stop(); flg.bMagPhase=1; output.SetTypeSynchronize(flg); double similarity = evaluateSimilarity( smReferenceP2Spectrum.GetMagBuffer(), output.GetMagBuffer() ); CPPUNIT_ASSERT( smEqualityThreshold <= similarity ); CPPUNIT_ASSERT( smReferenceP2Spectrum.GetSpectralRange() == output.GetSpectralRange() ); } void test_WithNonPowerOfTwoInput() { CLAM::Audio input; CLAM::Spectrum output; CLAM::FFTConfig processingConfig; setupSine_F0400Hz_SR8kHz_884samples( input ); setupSpectrumToStoreFFTOutput( output ); output.SetSize( CLAM::TSize(input.GetSize()/2 + 1) ); processingConfig.SetAudioSize( input.GetSize() ); mProcessing->Configure( processingConfig ); mProcessing->Start(); mProcessing->Do( input, output ); mProcessing->Stop(); double similarity = evaluateSimilarity( smReferenceNP2Spectrum.GetMagBuffer(), output.GetMagBuffer() ); CPPUNIT_ASSERT( smEqualityThreshold <= similarity ); CPPUNIT_ASSERT( smReferenceP2Spectrum.GetSpectralRange() == output.GetSpectralRange() ); } void test_WithNonPowerOfTwoInput_fails() { CLAM::Audio input; CLAM::Spectrum output; CLAM::FFTConfig processingConfig; setupSine_F0400Hz_SR8kHz_884samples( input ); setupSpectrumToStoreFFTOutput( output ); output.SetSize( CLAM::TSize(input.GetSize()/2 + 1) ); processingConfig.SetAudioSize( input.GetSize() ); CPPUNIT_ASSERT_EQUAL( false, mProcessing->Configure( processingConfig ) ); } }; double FFTFunctionalTest::smEqualityThreshold = 0.99999999999; // More accurate as close to 1 bool FFTFunctionalTest::smBack2BackDataLoaded = false; CLAM::Spectrum FFTFunctionalTest::smReferenceP2Spectrum; CLAM::Spectrum FFTFunctionalTest::smReferenceNP2Spectrum; #ifdef USE_FFTW3 class FFTW3FunctionalTest; CPPUNIT_TEST_SUITE_REGISTRATION( FFTW3FunctionalTest ); class FFTW3FunctionalTest : public FFTFunctionalTest { CPPUNIT_TEST_SUITE( FFTW3FunctionalTest ); CPPUNIT_TEST( test_WithPowerOfTwoInput ); CPPUNIT_TEST( test_WithNonPowerOfTwoInput ); CPPUNIT_TEST( test_WithComplex ); CPPUNIT_TEST( test_WithPolar ); CPPUNIT_TEST( test_WithBPF ); CPPUNIT_TEST_SUITE_END(); protected: virtual const std::string getProcessing() { return "FFT_fftw3"; } }; #endif #ifdef USE_FFTW class FFTWFunctionalTest; CPPUNIT_TEST_SUITE_REGISTRATION( FFTWFunctionalTest ); class FFTWFunctionalTest : public FFTFunctionalTest { CPPUNIT_TEST_SUITE( FFTWFunctionalTest ); CPPUNIT_TEST( test_WithPowerOfTwoInput ); CPPUNIT_TEST( test_WithNonPowerOfTwoInput ); CPPUNIT_TEST( test_WithComplex ); CPPUNIT_TEST( test_WithPolar ); CPPUNIT_TEST( test_WithBPF ); CPPUNIT_TEST_SUITE_END(); protected: virtual const std::string getProcessing() { return "FFT_rfftw"; } }; #endif class FFTOouraFunctionalTest; CPPUNIT_TEST_SUITE_REGISTRATION( FFTOouraFunctionalTest ); class FFTOouraFunctionalTest : public FFTFunctionalTest { CPPUNIT_TEST_SUITE( FFTOouraFunctionalTest ); CPPUNIT_TEST( test_WithPowerOfTwoInput ); CPPUNIT_TEST( test_WithNonPowerOfTwoInput_fails ); CPPUNIT_TEST( test_WithComplex ); CPPUNIT_TEST( test_WithPolar ); CPPUNIT_TEST( test_WithBPF ); CPPUNIT_TEST_SUITE_END(); protected: virtual const std::string getProcessing() { return "FFT_ooura"; } }; class FFTNumRecFunctionalTest; CPPUNIT_TEST_SUITE_REGISTRATION( FFTNumRecFunctionalTest ); class FFTNumRecFunctionalTest : public FFTFunctionalTest { CPPUNIT_TEST_SUITE( FFTNumRecFunctionalTest ); CPPUNIT_TEST( test_WithPowerOfTwoInput ); CPPUNIT_TEST( test_WithNonPowerOfTwoInput_fails ); CPPUNIT_TEST( test_WithComplex ); CPPUNIT_TEST( test_WithPolar ); CPPUNIT_TEST( test_WithBPF ); CPPUNIT_TEST_SUITE_END(); protected: virtual const std::string getProcessing() { return "FFT_numrec"; } }; } clam-1.4.0/test/FunctionalTests/ProcessingTests/TestStreamingSMSAnalysisSynthesis.cxx0000644000000000000000000001670611330303527027716 0ustar rootroot #include #include "cppUnitHelper.hxx" #include "AudioCollator.hxx" #include "SimpleOscillator.hxx" #include "SMSAnalysisCore.hxx" #include "SMSSynthesis.hxx" #include "Audio.hxx" #include "AudioOutPort.hxx" #include "MonoAudioFileReader.hxx" #include "MonoAudioFileWriter.hxx" #include "Network.hxx" #include "MonoOfflineNetworkPlayer.hxx" namespace CLAMTest { class TestStreamingSMSAnalysisSynthesis; CPPUNIT_TEST_SUITE_REGISTRATION( TestStreamingSMSAnalysisSynthesis ); class TestStreamingSMSAnalysisSynthesis : public CppUnit::TestFixture { public: CPPUNIT_TEST_SUITE( TestStreamingSMSAnalysisSynthesis ); CPPUNIT_TEST( testAnalysisSynthesis ); CPPUNIT_TEST( testAnalysisSynthesisInaNetwork ); CPPUNIT_TEST_SUITE_END(); public: void setUp() { ConfigureAnalysisSynthesis(); } private: CLAM::SMSAnalysisCore mAnalysis; CLAM::SMSSynthesis mSynthesis; const int helperResAnalWindowSize() { return 1025; } const int helperAnalWindowSize() { return 2049; } const int helperAnalHopSize() {return 256;} void ConfigureAnalysisSynthesis() { /*global parameters*/ int analWindowSize = 2049; int resAnalWindowSize = 1025; int analHopSize = 256; // analHopSize= (resAnalWindowSize-1)/2 ; int synthFrameSize = analHopSize; int analZeroPaddingFactor= 2; // SMS Analysis configuration CLAM::SMSAnalysisConfig analConfig; analConfig.SetSinWindowSize(analWindowSize); analConfig.SetHopSize(analHopSize); // analConfig.SetSinWindowType(mGlobalConfig.GetAnalysisWindowType()); analConfig.SetSinZeroPadding(analZeroPaddingFactor); analConfig.SetResWindowSize(resAnalWindowSize); // analConfig.SetResWindowType(mGlobalConfig.GetResAnalysisWindowType()); // analConfig.GetPeakDetect().SetMagThreshold(mGlobalConfig.GetAnalysisPeakDetectMagThreshold()); // analConfig.GetPeakDetect().SetMaxFreq(mGlobalConfig.GetAnalysisPeakDetectMaxFreq()); // analConfig.GetSinTracking().SetIsHarmonic(mGlobalConfig.GetAnalysisHarmonic()); // analConfig.GetFundFreqDetect().SetReferenceFundFreq(mGlobalConfig.GetAnalysisReferenceFundFreq()); // analConfig.GetFundFreqDetect().SetLowestFundFreq(mGlobalConfig.GetAnalysisLowestFundFreq()); // analConfig.GetFundFreqDetect().SetHighestFundFreq(mGlobalConfig.GetAnalysisHighestFundFreq()); CLAM::SMSSynthesisConfig synthConfig; synthConfig.SetAnalWindowSize(resAnalWindowSize); synthConfig.SetFrameSize(synthFrameSize); synthConfig.SetHopSize(synthFrameSize); // mAnalysis.Configure(analConfig); // mSynthesis.Configure(synthConfig); } //TODO: fix. it runs but produces a broken sinusoidal void testAnalysisSynthesis() //no segment, no frame just streaming inner data { // CLAM::ErrAssertionFailed::breakpointInCLAMAssertEnabled = true; int frameSize = 512; CLAM::MonoAudioFileReader audioProvider; CLAM::MonoAudioFileReaderConfig readercfg; CLAM::MonoAudioFileWriter audioWriter; CLAM::MonoAudioFileWriterConfig writercfg; readercfg.SetSourceFile(GetTestDataDirectory("sine.wav")); audioProvider.GetOutPort("Samples Read").SetSize( frameSize ); audioProvider.GetOutPort("Samples Read").SetHop(frameSize); const std::string outputFile(GetTestDataDirectory("SMSTests/out_analysis-synthesis-streaming_sine")); audioProvider.Configure( readercfg ); writercfg.SetTargetFile(outputFile+"_result.wav"); audioWriter.Configure( writercfg ); CLAM::SMSAnalysisCore analysis; CLAM::SMSSynthesis synthesis; analysis.Configure( helperAnalysisConfigInstance() ); synthesis.Configure( helperSynthesisConfigInstance() ); CLAM::ConnectPorts(audioProvider, "Samples Read", mAnalysis, "Input Audio"); CLAM::ConnectPorts(mAnalysis, "Sinusoidal Peaks", synthesis, "InputSinPeaks"); CLAM::ConnectPorts(mAnalysis, "Residual Spectrum", synthesis, "InputResSpectrum"); CLAM::ConnectPorts(synthesis, "OutputAudio", audioWriter, "Samples Write" ); audioProvider.Start(); audioWriter.Start(); mAnalysis.Start(); synthesis.Start(); // Processings firings CLAM_ASSERT(audioProvider.GetOutPort("Samples Read").CanProduce(), "mono audio file reader should have provided audio"); while (audioProvider.Do()) { mAnalysis.Do(); if (synthesis.CanConsumeAndProduce()) { synthesis.Do(); } if (audioWriter.CanConsumeAndProduce()) { audioWriter.Do(); } } audioWriter.Stop(); std::string whyDifferents; bool equals=helperCompareTwoAudioFiles( outputFile+".wav", outputFile+"_result.wav", whyDifferents); CPPUNIT_ASSERT_MESSAGE(whyDifferents, equals); } // helper methods for the network tests const CLAM::SMSAnalysisConfig& helperAnalysisConfigInstance() { int analHopSize = 256; // analHopSize= (resAnalWindowSize-1)/2 ; // int synthFrameSize = analHopSize; int analZeroPaddingFactor= 2; // SMS Analysis configuration static CLAM::SMSAnalysisConfig analConfig; analConfig.SetSinWindowSize(helperAnalWindowSize() ); analConfig.SetHopSize(analHopSize); // analConfig.SetSinWindowType(mGlobalConfig.GetAnalysisWindowType()); analConfig.SetSinZeroPadding(analZeroPaddingFactor); analConfig.SetResWindowSize( helperResAnalWindowSize() ); // analConfig.SetResWindowType(mGlobalConfig.GetResAnalysisWindowType()); // analConfig.GetPeakDetect().SetMagThreshold(mGlobalConfig.GetAnalysisPeakDetectMagThreshold()); // analConfig.GetPeakDetect().SetMaxFreq(mGlobalConfig.GetAnalysisPeakDetectMaxFreq()); // analConfig.GetSinTracking().SetIsHarmonic(mGlobalConfig.GetAnalysisHarmonic()); // analConfig.GetFundFreqDetect().SetReferenceFundFreq(mGlobalConfig.GetAnalysisReferenceFundFreq()); // analConfig.GetFundFreqDetect().SetLowestFundFreq(mGlobalConfig.GetAnalysisLowestFundFreq()); // analConfig.GetFundFreqDetect().SetHighestFundFreq(mGlobalConfig.GetAnalysisHighestFundFreq()); return analConfig; } const CLAM::SMSSynthesisConfig & helperSynthesisConfigInstance() { static CLAM::SMSSynthesisConfig synthConfig; int synthFrameSize = helperAnalHopSize(); synthConfig.SetAnalWindowSize( helperResAnalWindowSize() ); synthConfig.SetFrameSize(synthFrameSize); synthConfig.SetHopSize(synthFrameSize); return synthConfig; } void testAnalysisSynthesisInaNetwork() { //CLAM::ErrAssertionFailed::breakpointInCLAMAssertEnabled = true; CLAM::Network net; CLAM::MonoOfflineNetworkPlayer * player = new CLAM::MonoOfflineNetworkPlayer; net.SetPlayer( player ); // network owns the player memory net.AddProcessing( "Source", new CLAM::AudioSource ); net.AddProcessing( "Sink", new CLAM::AudioSink ); net.AddProcessing( "Analysis", new CLAM::SMSAnalysisCore ); net.AddProcessing( "Synthesis", new CLAM::SMSSynthesis ); net.ConnectPorts("Source.1", "Analysis.Input Audio"); net.ConnectPorts("Analysis.Sinusoidal Peaks", "Synthesis.InputSinPeaks"); net.ConnectPorts("Analysis.Residual Spectrum", "Synthesis.InputResSpectrum"); net.ConnectPorts("Synthesis.OutputAudio", "Sink.1"); net.ConfigureProcessing("Analysis", helperAnalysisConfigInstance() ); net.ConfigureProcessing("Synthesis", helperSynthesisConfigInstance() ); std::string inputFile = GetTestDataDirectory("Elvis.wav"); std::string baseOutputFile = GetTestDataDirectory("SMSTests/out_sms_net_stream"); player->AddInputFile(inputFile); player->AddOutputFile(baseOutputFile+"_result.wav"); net.Start(); net.Stop(); std::string whyDifferents; bool equals=helperCompareTwoAudioFiles( baseOutputFile+".wav", baseOutputFile+"_result.wav", whyDifferents); CPPUNIT_ASSERT_MESSAGE(whyDifferents, equals); std::cout << "end of the test \n"; } }; } // namespace CLAMTest clam-1.4.0/test/FunctionalTests/ProcessingTests/similarityHelper.hxx0000644000000000000000000000171710610720021024443 0ustar rootroot#ifndef __SIMILARITY_HELPER__ #define __SIMILARITY_HELPER__ #include "Err.hxx" #include "Array.hxx" namespace CLAM { class SpectralPeakArray; } namespace CLAMTest { class DataSizeMismatch : public CLAM::Err { public: DataSizeMismatch() throw(); DataSizeMismatch( const char* msg ) throw(); ~DataSizeMismatch() throw(); }; /** * Evaluates the Pearson R correlation value * between input arrays. The formula for computing it is as follows: * * r(x,y) = Cov( x,y ) / stdDeviation(x)*stdDeviation(y); */ double evaluateSimilarity( const CLAM::DataArray& left, const CLAM::DataArray& right ) throw ( DataSizeMismatch ); /** * Flattens the input spectral peak array into a floating-point values * array, so its representation is more amenable to be compared by * the similarity criterion */ void flattenSpectralPeakArray( const CLAM::SpectralPeakArray& in, CLAM::DataArray& out ); } #endif // similarityHelper.hxx clam-1.4.0/test/FunctionalTests/ProcessingTests/TestMIDIIO.cxx0000644000000000000000000000321511101735156022730 0ustar rootroot#include "MIDIManager.hxx" #include "MIDIInControl.hxx" #include "MIDIOutControl.hxx" #include "MIDIClocker.hxx" #include using namespace CLAM; main() { char* indevice = "file:zefile.mid"; char* outdevice = "textfile:test.txt"; MIDIManager manager; MIDIInConfig inNoteCfg; MIDIOutConfig outNoteCfg; MIDIClockerConfig inpClockerCfg; MIDIClockerConfig outClockerCfg; inpClockerCfg.SetDevice(indevice); outClockerCfg.SetDevice(outdevice); MIDIClocker inpClocker(inpClockerCfg); MIDIClocker outClocker(outClockerCfg); inNoteCfg.SetDevice(indevice); inNoteCfg.SetMessage(MIDI::eNoteOnOff); outNoteCfg.SetDevice(outdevice); outNoteCfg.SetMessage(MIDI::eNoteOnOff); MIDIInControl inNote(inNoteCfg); MIDIOutControl outNote(outNoteCfg); //control for stoping at eof MIDIInConfig inStopCfg; inStopCfg.SetDevice(indevice); inStopCfg.SetChannel(CLAM::MIDI::eStop); //it is a sys message that uses channel byte for actual data inStopCfg.SetMessage(CLAM::MIDI::eSystem); MIDIInControl inStop(inStopCfg); FloatInControl stopReceiver("stop-receiver"); inStop.GetOutControl(0).AddLink( &stopReceiver); inNote.GetOutControl(0).AddLink( &outNote.GetInControl(0)); inNote.GetOutControl(1).AddLink( &outNote.GetInControl(1)); inNote.GetOutControl(2).AddLink( &outNote.GetInControl(2)); manager.Start(); TTime curTime = 0; while (stopReceiver.GetLastValue()==0) { //we send a timing control to the MIDI clocker SendFloatToInControl(inpClocker,0,curTime); SendFloatToInControl(outClocker,0,curTime); //we check for new events in the MIDI manager manager.Check(); //we increment the time counter curTime ++; } } clam-1.4.0/test/FunctionalTests/ProcessingTests/TestSpectralPeakDetect.cxx0000644000000000000000000001557010610720021025461 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "similarityHelper.hxx" #include "Spectrum.hxx" #include "SpectralAnalysisExampleHelper.hxx" #include "SpectralPeakDetectExampleHelper.hxx" #include "SpectralPeakArray.hxx" #include "SpectralPeakDetect.hxx" #include "XMLStorage.hxx" #include namespace CLAMTest { class SpectralPeakDetectFunctionalTest; CPPUNIT_TEST_SUITE_REGISTRATION( SpectralPeakDetectFunctionalTest ); class SpectralPeakDetectFunctionalTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( SpectralPeakDetectFunctionalTest ); CPPUNIT_TEST( test_ProofOfConcept ); CPPUNIT_TEST( test_DetectsSamePeaksFromNoiseSignal ); CPPUNIT_TEST_SUITE_END(); protected: static double smSimilarityThreshold; static bool smBack2BackDataLoaded; static CLAM::SpectralPeakArray smReferenceSpectralPeakArray; static CLAM::Spectrum smReferenceSpectrum; static CLAMExamples::SpectralPeaksSet smReferenceSpectralPeaksSet; std::string mPathToTestData; protected: // Auxiliary methods static void loadBack2BackDataset( const std::string& pathToTestData ) { if ( !smBack2BackDataLoaded ) { CLAM::XMLStorage::Restore( smReferenceSpectralPeakArray, pathToTestData + "OneSineSpectrum_RectWindow_P2_Peaks.xml" ); CLAM::XMLStorage::Restore( smReferenceSpectrum, pathToTestData + "OneSineSpectrum_RectWindow_P2.xml" ); CLAM::XMLStorage::Restore( smReferenceSpectralPeaksSet, pathToTestData + "DetectedPeaks_0001.xml" ); smBack2BackDataLoaded = true; } } public: void setUp() { mPathToTestData = GetTestDataDirectory("spectralData/"); loadBack2BackDataset( mPathToTestData ); } void tearDown() { } private: void test_ProofOfConcept() { CLAM::SpectralPeakArray detectedPeaks; detectedPeaks.SetScale( CLAM::EScale::eLog ); CLAM::SpectralPeakDetectConfig processingConfig; // default CLAM::SpectralPeakDetect processing; smReferenceSpectrum.ToDB(); processing.Configure( processingConfig ); // (*processing.GetInPorts().Begin())->Attach( smReferenceSpectrum ); // (*processing.GetOutPorts().Begin())->Attach( detectedPeaks ); processing.Start(); processing.Do( smReferenceSpectrum, detectedPeaks ); processing.Stop(); CLAM::DataArray flattenedReference; CLAM::DataArray flattenedResult; flattenSpectralPeakArray( smReferenceSpectralPeakArray, flattenedReference ); flattenSpectralPeakArray( detectedPeaks, flattenedResult ); double similarity = evaluateSimilarity( flattenedReference, flattenedResult ); // We dump the detected peaks if the similitude between // the reference dataset and the detected peaks is outside // our confidence interval if ( smSimilarityThreshold > similarity ) { /* CLAMVM::SpectrumAndPeaksPlot refDataPlot( "plot_1" ); refDataPlot.SetPosition( 0, 100 ); refDataPlot.SetSize( 300, 300 ); refDataPlot.SetYRange( -80, 500 ); refDataPlot.SetLabel( "Reference dataset results" ); refDataPlot.SetData( smReferenceSpectrum, smReferenceSpectralPeakArray ); CLAMVM::SpectrumAndPeaksPlot actualDataPlot( "plot_2" ); actualDataPlot.SetPosition( 320, 100 ); actualDataPlot.SetSize( 300, 300 ); actualDataPlot.SetYRange( -80, 500 ); actualDataPlot.SetLabel( "Obtained peaks" ); actualDataPlot.SetData( smReferenceSpectrum, detectedPeaks ); CLAMVM::SystemPlots::DisplayAll(); */ CLAM::XMLStorage::Dump( detectedPeaks, "PeaksFailedToPassTest", "detectedPeaks_ProofOfConcept.xml" ); } CPPUNIT_ASSERT( smSimilarityThreshold <= similarity ); } void test_DetectsSamePeaksFromNoiseSignal() { // Load spectral analysis needed for repeating the peak detection // process CLAMExamples::SpectralAnalysis specAnalysis; CLAM::XMLStorage::Restore( specAnalysis, mPathToTestData+smReferenceSpectralPeaksSet.GetSpectralAnalysis() ); CLAM::SpectralPeakDetect peakDetector; peakDetector.Configure( smReferenceSpectralPeaksSet.GetPeakDetectionSettings() ); CLAMExamples::SpectralPeaksSet detectedPeaks; CLAM::SpectralPeakArray tmpPeakArray; tmpPeakArray.SetScale( CLAM::EScale::eLog ); peakDetector.Start(); CLAMExamples::SpectralAnalysis::FramesContainer::iterator i = specAnalysis.GetResultingFrames().begin(); while( i!= specAnalysis.GetResultingFrames().end() ) { i->ToDB(); peakDetector.Do( *i, tmpPeakArray ); detectedPeaks.GetDetectedPeaks().push_back( tmpPeakArray ); i++; } peakDetector.Stop(); // Let's check that the detected peaks resemble the reference peaks std::ofstream log; log.open( "TestSpectralPeakDetect_DetectsSamePeaksFromNoiseSignal.log" ); CLAMExamples::SpectralPeaksSet::SpectralPeaksList::iterator k = smReferenceSpectralPeaksSet.GetDetectedPeaks().begin(); CLAMExamples::SpectralPeaksSet::SpectralPeaksList::iterator l = detectedPeaks.GetDetectedPeaks().begin(); bool everythingWentOK = true; int frameCounter = 0; while ( k != smReferenceSpectralPeaksSet.GetDetectedPeaks().end() && l != detectedPeaks.GetDetectedPeaks().end() ) { CLAM::DataArray flattenedReference; CLAM::DataArray flattenedResult; flattenSpectralPeakArray( *k, flattenedReference ); flattenSpectralPeakArray( *l, flattenedResult ); try { double similarity = evaluateSimilarity( flattenedReference, flattenedResult ); if ( smSimilarityThreshold > similarity ) { log << "Frame #" << frameCounter << ": Was dissimilar "; log << "similarity index was " << similarity*100. << "%" << std::endl; everythingWentOK = false; } } catch( CLAMTest::DataSizeMismatch& error ) { log << "Frame #" << frameCounter << ": Could not be compared "; log << "revise spectral peak arrays visually" << std::endl; everythingWentOK = false; } frameCounter++; k++; l++; } if ( frameCounter != smReferenceSpectralPeaksSet.GetDetectedPeaks().size() ) { log << "there was a difference of "; log << smReferenceSpectralPeaksSet.GetDetectedPeaks().size() - frameCounter; log << " between reference peaks in frame list and the actual" << std::endl; } log.close(); CPPUNIT_ASSERT_EQUAL( true, everythingWentOK ); } }; double SpectralPeakDetectFunctionalTest::smSimilarityThreshold = 0.9999; bool SpectralPeakDetectFunctionalTest::smBack2BackDataLoaded = false; CLAM::Spectrum SpectralPeakDetectFunctionalTest::smReferenceSpectrum; CLAM::SpectralPeakArray SpectralPeakDetectFunctionalTest::smReferenceSpectralPeakArray; CLAMExamples::SpectralPeaksSet SpectralPeakDetectFunctionalTest::smReferenceSpectralPeaksSet; } clam-1.4.0/test/FunctionalTests/ProcessingTests/TestMultiChannelAudioFileReader.cxx0000644000000000000000000011344711213763360027261 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "AudioFile.hxx" #include "MultiChannelAudioFileReaderConfig.hxx" #include "MultiChannelAudioFileReader.hxx" #include "MultiChannelAudioFileWriter.hxx" #include "Audio.hxx" #include "CLAM_Math.hxx" #include "AudioFileOpsTestsHelper.hxx" #include "similarityHelper.hxx" #include #include #include namespace CLAMTest { class MultiChannelAudioFileReaderFunctionalTest; CPPUNIT_TEST_SUITE_REGISTRATION( MultiChannelAudioFileReaderFunctionalTest ); class MultiChannelAudioFileReaderFunctionalTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( MultiChannelAudioFileReaderFunctionalTest ); // Configuration values checking tests CPPUNIT_TEST( testConfigure_ReturnsTrueWithJustFilename ); CPPUNIT_TEST( testConfigure_ReturnsFalseWithoutAudioFileInConfig ); CPPUNIT_TEST( testConfigure_ReturnsTrueWhenFileExists ); CPPUNIT_TEST( testConfigure_ReturnsFalseWhenFileDoesNotExist ); CPPUNIT_TEST( testConfigure_DefaultChannelSelection_ChannelsOK ); CPPUNIT_TEST( testConfigure_DefaultChannelSelection_PortNumberIsOK ); CPPUNIT_TEST( testConfigure_ManualChannelSelection_ChannelsOK ); CPPUNIT_TEST( testConfigure_ManualChannelSelection_PortNumberIsOK ); CPPUNIT_TEST( testConfigure_ReturnsFalse_ManualChannelSelection_TooMany ); CPPUNIT_TEST( testConfigure_ReturnsFalse_ManualChannelSelection_InvalidChannel ); // Do test cases CPPUNIT_TEST( testDo_PCM_JustOneFrame ); CPPUNIT_TEST( testDo_PCM_JustTwoFrames ); CPPUNIT_TEST( testDo_OggVorbis_JustOneFrame ); CPPUNIT_TEST( testDo_OggVorbis_JustTwoFrames ); CPPUNIT_TEST( test_MpegAudioFiles_128kbps_44kHz_AreDecoded_OK ); CPPUNIT_TEST( test_MpegAudioFiles_192kbps_44kHz_AreDecoded_OK ); CPPUNIT_TEST( test_MpegAudioFiles_64kbps_44kHz_AreDecoded_OK ); CPPUNIT_TEST( test_MpegAudioFiles_320kbps_44kHz_AreDecoded_OK ); CPPUNIT_TEST( test_MpegAudioFiles_LowVBR_44kHz_AreDecoded_OK ); CPPUNIT_TEST( test_MpegAudioFiles_AvgVBR_44kHz_AreDecoded_OK ); CPPUNIT_TEST( test_MpegAudioFiles_HighVBR_44kHz_AreDecoded_OK ); CPPUNIT_TEST( testDo_JustOneFrame_SampleRateIsOK ); CPPUNIT_TEST( testDo_JustTwoFrames_BeginTimesAreOK ); CPPUNIT_TEST_SUITE_END(); protected: // Attributes std::string mPathToTestData; protected: // Auxiliary methods public: // TestFixture interface void setUp() { mPathToTestData = GetTestDataDirectory(""); } void tearDown() { } private: // tests cases void testConfigure_ReturnsTrueWithJustFilename() { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"Elvis.wav" ); CLAM::MultiChannelAudioFileReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( true, configResult ); } void testConfigure_ReturnsFalseWithoutAudioFileInConfig() { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.RemoveSourceFile(); cfg.UpdateData(); CLAM::MultiChannelAudioFileReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( false, configResult ); } void testConfigure_ReturnsTrueWhenFileExists() { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); CLAM::MultiChannelAudioFileReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( true, configResult ); } void testConfigure_ReturnsFalseWhenFileDoesNotExist() { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"StereoTestFile-false.wav" ); CLAM::MultiChannelAudioFileReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( false, configResult ); } void testConfigure_DefaultChannelSelection_ChannelsOK() { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); CLAM::MultiChannelAudioFileReader proc; proc.Configure( cfg ); CLAM::MultiChannelAudioFileReaderConfig cfgToBeChecked = dynamic_cast< const CLAM::MultiChannelAudioFileReaderConfig& > ( proc.GetConfig() ); const std::vector< CLAM::TIndex >& channels = proc.GetSelectedChannels(); CPPUNIT_ASSERT_EQUAL ( channels.size(), size_t(proc.GetHeader().GetChannels()) ); bool allChannelsPresent = true; for ( unsigned i = 0; i < channels.size(); i++ ) allChannelsPresent &= (channels[i] == i); CPPUNIT_ASSERT_EQUAL( true, allChannelsPresent ); } void testConfigure_DefaultChannelSelection_PortNumberIsOK() { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); CLAM::MultiChannelAudioFileReader proc; proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( 2u, proc.GetNOutPorts()); } void testConfigure_ManualChannelSelection_ChannelsOK() { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.AddSelectedChannels(); cfg.UpdateData(); cfg.GetSelectedChannels().Resize( 2 ); cfg.GetSelectedChannels().SetSize( 2 ); cfg.GetSelectedChannels()[0] = 1; cfg.GetSelectedChannels()[1] = 0; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); CLAM::MultiChannelAudioFileReader proc; proc.Configure( cfg ); CLAM::MultiChannelAudioFileReaderConfig cfgToBeChecked = dynamic_cast< const CLAM::MultiChannelAudioFileReaderConfig& > ( proc.GetConfig() ); const std::vector< CLAM::TIndex >& channels = proc.GetSelectedChannels(); CPPUNIT_ASSERT_EQUAL ( channels.size(), size_t(cfg.GetSelectedChannels().Size()) ); bool allChannelsPresent = true; for (unsigned i = 0; i < channels.size(); i++ ) allChannelsPresent &= (channels[i] == cfg.GetSelectedChannels()[i] ); CPPUNIT_ASSERT_EQUAL( true, allChannelsPresent ); } void testConfigure_ManualChannelSelection_PortNumberIsOK() { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.AddSelectedChannels(); cfg.UpdateData(); cfg.GetSelectedChannels().Resize( 2 ); cfg.GetSelectedChannels().SetSize( 2 ); cfg.GetSelectedChannels()[0] = 1; cfg.GetSelectedChannels()[1] = 0; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); CLAM::MultiChannelAudioFileReader proc; proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( 2u, proc.GetNOutPorts()); } void testConfigure_ReturnsFalse_ManualChannelSelection_TooMany() { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.AddSelectedChannels(); cfg.UpdateData(); cfg.GetSelectedChannels().Resize( 3 ); cfg.GetSelectedChannels().SetSize( 3 ); cfg.GetSelectedChannels()[0] = 1; cfg.GetSelectedChannels()[1] = 0; cfg.GetSelectedChannels()[2] = 2; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); CLAM::MultiChannelAudioFileReader proc; bool cfgResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( false, cfgResult ); } void testConfigure_ReturnsFalse_ManualChannelSelection_InvalidChannel() { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.AddSelectedChannels(); cfg.UpdateData(); cfg.GetSelectedChannels().Resize( 2 ); cfg.GetSelectedChannels().SetSize( 2 ); cfg.GetSelectedChannels()[0] = 1; cfg.GetSelectedChannels()[1] = 65; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); CLAM::MultiChannelAudioFileReader proc; bool cfgResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( false, cfgResult ); } void testDo_PCM_JustOneFrame () { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); CLAM::MultiChannelAudioFileReader proc; proc.Configure( cfg ); std::vector samples(2); for ( int k = 0; k < 2; k++ ) samples[k].SetSize(256); proc.Start(); proc.Do(samples); proc.Stop(); double similarityLeft = 0.0, similarityRight = 0.0; fileSimilarity( cfg.GetSourceFile(), samples[0], samples[1], similarityLeft, similarityRight ); CPPUNIT_ASSERT( similarityLeft >= 0.9999 ); CPPUNIT_ASSERT( similarityRight >= 0.9999 ); } void testDo_PCM_JustTwoFrames() { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); CLAM::MultiChannelAudioFileReader proc; proc.Configure( cfg ); std::vector samples(2); for ( int k = 0; k < 2; k++ ) samples[k].SetSize(256); CLAM::DataArray prevLeftSamples; prevLeftSamples.Resize( 256 ); prevLeftSamples.SetSize( 256 ); CLAM::DataArray prevRightSamples; prevRightSamples.Resize( 256 ); prevRightSamples.SetSize( 256 ); proc.Start(); proc.Do(samples); // Save this frame to arrays std::copy( samples[0].GetBuffer().GetPtr(), samples[0].GetBuffer().GetPtr() + samples[0].GetBuffer().Size(), prevLeftSamples.GetPtr() ); std::copy( samples[1].GetBuffer().GetPtr(), samples[1].GetBuffer().GetPtr() + samples[1].GetBuffer().Size(), prevRightSamples.GetPtr() ); // call the Do again proc.Do(samples); proc.Stop(); double similarityLeft = 0.0, similarityRight = 0.0; similarityLeft = evaluateSimilarity( samples[0].GetBuffer(), prevLeftSamples ); similarityRight = evaluateSimilarity( samples[1].GetBuffer(), prevRightSamples ); CPPUNIT_ASSERT( fabs( -0.21055 // MRJ: value established by inspection - similarityLeft ) < 1e-4 ); CPPUNIT_ASSERT( fabs( -0.150199 // MRJ: value established by inspection - similarityRight ) < 1e-4 ); } void testDo_JustOneFrame_SampleRateIsOK() { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); CLAM::MultiChannelAudioFileReader proc; proc.Configure( cfg ); std::vector samples(2); samples[0].SetSize( 256 ); samples[1].SetSize( 256 ); proc.Start(); proc.Do(samples); proc.Stop(); CPPUNIT_ASSERT_EQUAL( proc.GetHeader().GetSampleRate(), samples[0].GetSampleRate() ); CPPUNIT_ASSERT_EQUAL( proc.GetHeader().GetSampleRate(), samples[1].GetSampleRate() ); } void testDo_JustTwoFrames_BeginTimesAreOK() { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); CLAM::MultiChannelAudioFileReader proc; proc.Configure( cfg ); std::vector samples(2); samples[0].SetSize( 256 ); samples[1].SetSize( 256 ); proc.Start(); proc.Do(samples); // Save Begin Time's CLAM::TTime firstLeftBeginTime = samples[0].GetBeginTime(); CLAM::TTime firstRightBeginTime = samples[1].GetBeginTime(); // call the Do again proc.Do(samples); proc.Stop(); CLAM::TTime truthLeft = CLAM::TTime( samples[0].GetSize() ) / proc.GetHeader().GetSampleRate() * 1000; CLAM::TTime yieldLeft = samples[0].GetBeginTime() - firstLeftBeginTime; CPPUNIT_ASSERT( fabs( truthLeft - yieldLeft ) < 1e-4 ); CLAM::TTime truthRight = CLAM::TTime( samples[1].GetSize() ) / proc.GetHeader().GetSampleRate() * 1000; CLAM::TTime yieldRight = samples[1].GetBeginTime() - firstRightBeginTime; CPPUNIT_ASSERT( fabs( truthRight - yieldRight ) < 1e-4 ); } void testDo_OggVorbis_JustOneFrame () { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"ElvisStereo.ogg" ); CLAM::MultiChannelAudioFileReader proc( cfg ); std::vector samples(2); samples[0].SetSize( 256 ); samples[1].SetSize( 256 ); proc.Start(); proc.Do(samples); proc.Stop(); double similarityLeft = 0.0, similarityRight = 0.0; fileSimilarity( cfg.GetSourceFile(), samples[0], samples[1], similarityLeft, similarityRight ); CPPUNIT_ASSERT( similarityLeft >= 0.9999 ); CPPUNIT_ASSERT( similarityRight >= 0.9999 ); } void testDo_OggVorbis_JustTwoFrames() { CLAM::MultiChannelAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"ElvisStereo.ogg" ); CLAM::MultiChannelAudioFileReader proc( cfg ); std::vector samples(2); samples[0].SetSize( 256 ); CLAM::DataArray prevLeftSamples; prevLeftSamples.Resize( 256 ); prevLeftSamples.SetSize( 256 ); samples[1].SetSize( 256 ); CLAM::DataArray prevRightSamples; prevRightSamples.Resize( 256 ); prevRightSamples.SetSize( 256 ); proc.Start(); proc.Do(samples); // Save this frame to arrays std::copy( samples[0].GetBuffer().GetPtr(), samples[0].GetBuffer().GetPtr() + samples[0].GetBuffer().Size(), prevLeftSamples.GetPtr() ); std::copy( samples[1].GetBuffer().GetPtr(), samples[1].GetBuffer().GetPtr() + samples[1].GetBuffer().Size(), prevRightSamples.GetPtr() ); // call the Do again proc.Do(samples); proc.Stop(); double similarityLeft = 0.0, similarityRight = 0.0; similarityLeft = evaluateSimilarity( samples[0].GetBuffer(), prevLeftSamples ); similarityRight = evaluateSimilarity( samples[1].GetBuffer(), prevRightSamples ); // MRJ: In Windows this is giving out very strange values /* std::cerr << "\n" << similarityLeft << "\n"; std::cerr << "\n" << similarityRight << "\n"; */ CPPUNIT_ASSERT( fabs( -0.840286 // MRJ: value established by inspection - similarityLeft ) < 1e-4 ); CPPUNIT_ASSERT( fabs( -0.840286 // MRJ: value established by inspection - similarityRight ) < 1e-4 ); } void test_MpegAudioFiles_128kbps_44kHz_AreDecoded_OK() { CLAM::MultiChannelAudioFileReaderConfig cfgReader; cfgReader.SetSourceFile( mPathToTestData+"test-stereo-decoding-128_44.mp3" ); CLAM::MultiChannelAudioFileReader procReader(cfgReader); CLAM::MultiChannelAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "test-mp3-128-44.wav" ); cfgWriter.SetSampleRate( procReader.GetHeader().GetSampleRate() ); cfgWriter.SetNChannels( procReader.GetHeader().GetChannels() ); CLAM::MultiChannelAudioFileWriter procWriter(cfgWriter); std::vector samples(2); samples[0].SetSize( 4096 ); samples[1].SetSize( 4096 ); procReader.Start(); procWriter.Start(); CLAM::TSize framesRead = 0; while( procReader.Do(samples) ) { framesRead++; procWriter.Do(samples); } procReader.Stop(); procWriter.Stop(); // Once written to disk, now we recover it, and // check it is the same frame by frame CLAM::MultiChannelAudioFileReader procReader2; cfgReader.SetSourceFile( "test-mp3-128-44.wav" ); CPPUNIT_ASSERT_EQUAL( true, procReader2.Configure( cfgReader ) ); std::vector samples2(2); samples2[0].SetSize( 4096 ); samples2[1].SetSize( 4096 ); procReader.Start(); procReader2.Start(); int framesChecked = 0; double maxSimLeft = -1e20; int maxSimLeftFrame = 0; double minSimLeft = 1e20; int minSimLeftFrame = 0; double averageSimLeft = 0.0; double maxSimRight = -1e20; int maxSimRightFrame = 0; double minSimRight = 1e20; int minSimRightFrame = 0; double averageSimRight = 0.0; while( procReader.Do(samples) && procReader2.Do(samples2) ) { framesChecked++; double simLeft = evaluateSimilarity( samples[0].GetBuffer(), samples2[0].GetBuffer() ); double simRight = evaluateSimilarity( samples[1].GetBuffer(), samples2[1].GetBuffer() ); if ( simLeft > maxSimLeft ) { maxSimLeft = simLeft; maxSimLeftFrame = framesChecked; } if ( simLeft < minSimLeft ) { minSimLeft = simLeft; minSimLeftFrame = framesChecked; } averageSimLeft += simLeft; if ( simRight > maxSimRight ) { maxSimRight = simRight; maxSimRightFrame = framesChecked; } if ( simRight < minSimRight ) { minSimRight = simRight; minSimRightFrame = framesChecked; } averageSimRight += simRight; CPPUNIT_ASSERT ( simLeft >= 0.99 ); CPPUNIT_ASSERT ( simRight >= 0.99 ); } procReader.Stop(); procReader2.Stop(); averageSimLeft *= (1.0/double(framesChecked)); averageSimRight *= (1.0/double(framesChecked)); /* std::cout << std::endl; std::cout << "Mp3 - 128kbps" << std::endl; std::cout << "Maximum Left similarity: " << maxSimLeft << " at " << maxSimLeftFrame; std::cout << std::endl; std::cout << "Minimum Left similarity: " << minSimLeft << " at " << minSimLeftFrame; std::cout << std::endl; std::cout << "Average Left similarity: " << averageSimLeft << std::endl; std::cout << std::endl; std::cout << "Maximum Right similarity: " << maxSimRight << " at " << maxSimRightFrame; std::cout << std::endl; std::cout << "Minimum Right similarity: " << minSimRight << " at " << minSimRightFrame; std::cout << std::endl; std::cout << "Average Right similarity: " << averageSimRight << std::endl; */ CPPUNIT_ASSERT_EQUAL( framesRead, framesChecked ); } void test_MpegAudioFiles_192kbps_44kHz_AreDecoded_OK() { CLAM::MultiChannelAudioFileReaderConfig cfgReader; cfgReader.SetSourceFile( mPathToTestData+"test-stereo-decoding-192_44.mp3" ); CLAM::MultiChannelAudioFileReader procReader(cfgReader); CLAM::MultiChannelAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "test-mp3-192-44.wav" ); cfgWriter.SetSampleRate( procReader.GetHeader().GetSampleRate() ); cfgWriter.SetNChannels( procReader.GetHeader().GetChannels() ); CLAM::MultiChannelAudioFileWriter procWriter(cfgWriter); std::vector samples(2); samples[0].SetSize( 4096 ); samples[1].SetSize( 4096 ); procReader.Start(); procWriter.Start(); CLAM::TSize framesRead = 0; while( procReader.Do(samples) ) { framesRead++; procWriter.Do(samples); } procReader.Stop(); procWriter.Stop(); // Once written to disk, now we recover it, and // check it is the same frame by frame CLAM::MultiChannelAudioFileReader procReader2; cfgReader.SetSourceFile( "test-mp3-192-44.wav" ); CPPUNIT_ASSERT_EQUAL( true, procReader2.Configure( cfgReader ) ); std::vector samples2(2); samples2[0].SetSize( 4096 ); samples2[1].SetSize( 4096 ); procReader.Start(); procReader2.Start(); int framesChecked = 0; double maxSimLeft = -1e20; int maxSimLeftFrame = 0; double minSimLeft = 1e20; int minSimLeftFrame = 0; double averageSimLeft = 0.0; double maxSimRight = -1e20; int maxSimRightFrame = 0; double minSimRight = 1e20; int minSimRightFrame = 0; double averageSimRight = 0.0; while( procReader.Do(samples) && procReader2.Do(samples2) ) { framesChecked++; double simLeft = evaluateSimilarity( samples[0].GetBuffer(), samples2[0].GetBuffer() ); double simRight = evaluateSimilarity( samples[1].GetBuffer(), samples2[1].GetBuffer() ); if ( simLeft > maxSimLeft ) { maxSimLeft = simLeft; maxSimLeftFrame = framesChecked; } if ( simLeft < minSimLeft ) { minSimLeft = simLeft; minSimLeftFrame = framesChecked; } averageSimLeft += simLeft; if ( simRight > maxSimRight ) { maxSimRight = simRight; maxSimRightFrame = framesChecked; } if ( simRight < minSimRight ) { minSimRight = simRight; minSimRightFrame = framesChecked; } averageSimRight += simRight; CPPUNIT_ASSERT ( simLeft >= 0.9 ); CPPUNIT_ASSERT ( simRight >= 0.9 ); } procReader.Stop(); procReader2.Stop(); averageSimLeft *= (1.0/double(framesChecked)); averageSimRight *= (1.0/double(framesChecked)); /* std::cout << std::endl; std::cout << "Mp3 - 196kbps" << std::endl; std::cout << "Maximum Left similarity: " << maxSimLeft << " at " << maxSimLeftFrame; std::cout << std::endl; std::cout << "Minimum Left similarity: " << minSimLeft << " at " << minSimLeftFrame; std::cout << std::endl; std::cout << "Average Left similarity: " << averageSimLeft << std::endl; std::cout << std::endl; std::cout << "Maximum Right similarity: " << maxSimRight << " at " << maxSimRightFrame; std::cout << std::endl; std::cout << "Minimum Right similarity: " << minSimRight << " at " << minSimRightFrame; std::cout << std::endl; std::cout << "Average Right similarity: " << averageSimRight << std::endl; */ CPPUNIT_ASSERT_EQUAL( framesRead, framesChecked ); } void test_MpegAudioFiles_64kbps_44kHz_AreDecoded_OK() { CLAM::MultiChannelAudioFileReaderConfig cfgReader; cfgReader.SetSourceFile( mPathToTestData+"test-stereo-decoding-64_44.mp3" ); CLAM::MultiChannelAudioFileReader procReader(cfgReader); if (not procReader.IsConfigured()) std::cout << "Reader: " << procReader.GetConfigErrorMessage() << std::endl; CLAM::MultiChannelAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "test-mp3-64-44.wav" ); cfgWriter.SetSampleRate( procReader.GetHeader().GetSampleRate() ); cfgWriter.SetNChannels( procReader.GetHeader().GetChannels() ); CLAM::MultiChannelAudioFileWriter procWriter(cfgWriter); if (not procWriter.IsConfigured()) std::cout << "Writer: " << procWriter.GetConfigErrorMessage() << std::endl; std::vector samples(2); samples[0].SetSize( 4096 ); samples[1].SetSize( 4096 ); procReader.Start(); procWriter.Start(); CLAM::TSize framesRead = 0; while( procReader.Do(samples) ) { framesRead++; procWriter.Do(samples); } procReader.Stop(); procWriter.Stop(); // Once written to disk, now we recover it, and // check it is the same frame by frame CLAM::MultiChannelAudioFileReader procReader2; cfgReader.SetSourceFile( "test-mp3-64-44.wav" ); CPPUNIT_ASSERT_EQUAL( true, procReader2.Configure( cfgReader ) ); std::vector samples2(2); samples2[0].SetSize( 4096 ); samples2[1].SetSize( 4096 ); procReader.Start(); procReader2.Start(); int framesChecked = 0; double maxSimLeft = -1e20; int maxSimLeftFrame = 0; double minSimLeft = 1e20; int minSimLeftFrame = 0; double averageSimLeft = 0.0; double maxSimRight = -1e20; int maxSimRightFrame = 0; double minSimRight = 1e20; int minSimRightFrame = 0; double averageSimRight = 0.0; while( procReader.Do(samples) && procReader2.Do(samples2) ) { framesChecked++; double simLeft = evaluateSimilarity( samples[0].GetBuffer(), samples2[0].GetBuffer() ); double simRight = evaluateSimilarity( samples[1].GetBuffer(), samples2[1].GetBuffer() ); if ( simLeft > maxSimLeft ) { maxSimLeft = simLeft; maxSimLeftFrame = framesChecked; } if ( simLeft < minSimLeft ) { minSimLeft = simLeft; minSimLeftFrame = framesChecked; } averageSimLeft += simLeft; if ( simRight > maxSimRight ) { maxSimRight = simRight; maxSimRightFrame = framesChecked; } if ( simRight < minSimRight ) { minSimRight = simRight; minSimRightFrame = framesChecked; } averageSimRight += simRight; CPPUNIT_ASSERT ( simLeft >= 0.9 ); CPPUNIT_ASSERT ( simRight >= 0.9 ); } procReader.Stop(); procReader2.Stop(); averageSimLeft *= (1.0/double(framesChecked)); averageSimRight *= (1.0/double(framesChecked)); /* std::cout << std::endl; std::cout << "Mp3 - 64kbps" << std::endl; std::cout << "Maximum Left similarity: " << maxSimLeft << " at " << maxSimLeftFrame; std::cout << std::endl; std::cout << "Minimum Left similarity: " << minSimLeft << " at " << minSimLeftFrame; std::cout << std::endl; std::cout << "Average Left similarity: " << averageSimLeft << std::endl; std::cout << std::endl; std::cout << "Maximum Right similarity: " << maxSimRight << " at " << maxSimRightFrame; std::cout << std::endl; std::cout << "Minimum Right similarity: " << minSimRight << " at " << minSimRightFrame; std::cout << std::endl; std::cout << "Average Right similarity: " << averageSimRight << std::endl; */ CPPUNIT_ASSERT_EQUAL( framesRead, framesChecked ); } void test_MpegAudioFiles_320kbps_44kHz_AreDecoded_OK() { CLAM::MultiChannelAudioFileReaderConfig cfgReader; cfgReader.SetSourceFile( mPathToTestData+"test-stereo-decoding-320_44.mp3" ); CLAM::MultiChannelAudioFileReader procReader(cfgReader); CLAM::MultiChannelAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "test-mp3-320-44.wav" ); cfgWriter.SetSampleRate( procReader.GetHeader().GetSampleRate() ); cfgWriter.SetNChannels( procReader.GetHeader().GetChannels() ); CLAM::MultiChannelAudioFileWriter procWriter(cfgWriter); std::vector samples(2); samples[0].SetSize( 4096 ); samples[1].SetSize( 4096 ); procReader.Start(); procWriter.Start(); CLAM::TSize framesRead = 0; while( procReader.Do(samples) ) { framesRead++; procWriter.Do(samples); } procReader.Stop(); procWriter.Stop(); // Once written to disk, now we recover it, and // check it is the same frame by frame CLAM::MultiChannelAudioFileReader procReader2; cfgReader.SetSourceFile( "test-mp3-320-44.wav" ); CPPUNIT_ASSERT_EQUAL( true, procReader2.Configure( cfgReader ) ); std::vector samples2(2); samples2[0].SetSize( 4096 ); samples2[1].SetSize( 4096 ); procReader.Start(); procReader2.Start(); int framesChecked = 0; double maxSimLeft = -1e20; int maxSimLeftFrame = 0; double minSimLeft = 1e20; int minSimLeftFrame = 0; double averageSimLeft = 0.0; double maxSimRight = -1e20; int maxSimRightFrame = 0; double minSimRight = 1e20; int minSimRightFrame = 0; double averageSimRight = 0.0; while( procReader.Do(samples) && procReader2.Do(samples2) ) { framesChecked++; double simLeft = evaluateSimilarity( samples[0].GetBuffer(), samples2[0].GetBuffer() ); double simRight = evaluateSimilarity( samples[1].GetBuffer(), samples2[1].GetBuffer() ); if ( simLeft > maxSimLeft ) { maxSimLeft = simLeft; maxSimLeftFrame = framesChecked; } if ( simLeft < minSimLeft ) { minSimLeft = simLeft; minSimLeftFrame = framesChecked; } averageSimLeft += simLeft; if ( simRight > maxSimRight ) { maxSimRight = simRight; maxSimRightFrame = framesChecked; } if ( simRight < minSimRight ) { minSimRight = simRight; minSimRightFrame = framesChecked; } averageSimRight += simRight; CPPUNIT_ASSERT ( simLeft >= 0.9 ); CPPUNIT_ASSERT ( simRight >= 0.9 ); } procReader.Stop(); procReader2.Stop(); averageSimLeft *= (1.0/double(framesChecked)); averageSimRight *= (1.0/double(framesChecked)); /* std::cout << std::endl; std::cout << "Mp3 - 320kbps" << std::endl; std::cout << "Maximum Left similarity: " << maxSimLeft << " at " << maxSimLeftFrame; std::cout << std::endl; std::cout << "Minimum Left similarity: " << minSimLeft << " at " << minSimLeftFrame; std::cout << std::endl; std::cout << "Average Left similarity: " << averageSimLeft << std::endl; std::cout << std::endl; std::cout << "Maximum Right similarity: " << maxSimRight << " at " << maxSimRightFrame; std::cout << std::endl; std::cout << "Minimum Right similarity: " << minSimRight << " at " << minSimRightFrame; std::cout << std::endl; std::cout << "Average Right similarity: " << averageSimRight << std::endl; */ CPPUNIT_ASSERT_EQUAL( framesRead, framesChecked ); } void test_MpegAudioFiles_LowVBR_44kHz_AreDecoded_OK() { CLAM::MultiChannelAudioFileReaderConfig cfgReader; cfgReader.SetSourceFile( mPathToTestData+"test-stereo-decoding-LowVBR_44.mp3" ); CLAM::MultiChannelAudioFileReader procReader(cfgReader); CLAM::MultiChannelAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "test-mp3-LowVBR-44.wav" ); cfgWriter.SetSampleRate( procReader.GetHeader().GetSampleRate() ); cfgWriter.SetNChannels( procReader.GetHeader().GetChannels() ); CLAM::MultiChannelAudioFileWriter procWriter(cfgWriter); std::vector samples(2); samples[0].SetSize( 4096 ); samples[1].SetSize( 4096 ); procReader.Start(); procWriter.Start(); CLAM::TSize framesRead = 0; while( procReader.Do(samples) ) { framesRead++; procWriter.Do(samples); } procReader.Stop(); procWriter.Stop(); // Once written to disk, now we recover it, and // check it is the same frame by frame CLAM::MultiChannelAudioFileReader procReader2; cfgReader.SetSourceFile( "test-mp3-LowVBR-44.wav" ); CPPUNIT_ASSERT_EQUAL( true, procReader2.Configure( cfgReader ) ); std::vector samples2(2); samples2[0].SetSize( 4096 ); samples2[1].SetSize( 4096 ); procReader.Start(); procReader2.Start(); int framesChecked = 0; double maxSimLeft = -1e20; int maxSimLeftFrame = 0; double minSimLeft = 1e20; int minSimLeftFrame = 0; double averageSimLeft = 0.0; double maxSimRight = -1e20; int maxSimRightFrame = 0; double minSimRight = 1e20; int minSimRightFrame = 0; double averageSimRight = 0.0; while( procReader.Do(samples) && procReader2.Do(samples2) ) { framesChecked++; double simLeft = evaluateSimilarity( samples[0].GetBuffer(), samples2[0].GetBuffer() ); double simRight = evaluateSimilarity( samples[1].GetBuffer(), samples2[1].GetBuffer() ); if ( simLeft > maxSimLeft ) { maxSimLeft = simLeft; maxSimLeftFrame = framesChecked; } if ( simLeft < minSimLeft ) { minSimLeft = simLeft; minSimLeftFrame = framesChecked; } averageSimLeft += simLeft; if ( simRight > maxSimRight ) { maxSimRight = simRight; maxSimRightFrame = framesChecked; } if ( simRight < minSimRight ) { minSimRight = simRight; minSimRightFrame = framesChecked; } averageSimRight += simRight; CPPUNIT_ASSERT ( simLeft >= 0.9 ); CPPUNIT_ASSERT ( simRight >= 0.9 ); } procReader.Stop(); procReader2.Stop(); averageSimLeft *= (1.0/double(framesChecked)); averageSimRight *= (1.0/double(framesChecked)); /* std::cout << std::endl; std::cout << "Mp3 - LowVBR" << std::endl; std::cout << "Maximum Left similarity: " << maxSimLeft << " at " << maxSimLeftFrame; std::cout << std::endl; std::cout << "Minimum Left similarity: " << minSimLeft << " at " << minSimLeftFrame; std::cout << std::endl; std::cout << "Average Left similarity: " << averageSimLeft << std::endl; std::cout << std::endl; std::cout << "Maximum Right similarity: " << maxSimRight << " at " << maxSimRightFrame; std::cout << std::endl; std::cout << "Minimum Right similarity: " << minSimRight << " at " << minSimRightFrame; std::cout << std::endl; std::cout << "Average Right similarity: " << averageSimRight << std::endl; */ CPPUNIT_ASSERT_EQUAL( framesRead, framesChecked ); } void test_MpegAudioFiles_HighVBR_44kHz_AreDecoded_OK() { CLAM::MultiChannelAudioFileReaderConfig cfgReader; cfgReader.SetSourceFile( mPathToTestData+"test-stereo-decoding-HighVBR_44.mp3" ); CLAM::MultiChannelAudioFileReader procReader(cfgReader); CLAM::MultiChannelAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "test-mp3-HighVBR-44.wav" ); cfgWriter.SetSampleRate( procReader.GetHeader().GetSampleRate() ); cfgWriter.SetNChannels( procReader.GetHeader().GetChannels() ); CLAM::MultiChannelAudioFileWriter procWriter(cfgWriter); std::vector samples(2); samples[0].SetSize( 4096 ); samples[1].SetSize( 4096 ); procReader.Start(); procWriter.Start(); CLAM::TSize framesRead = 0; while( procReader.Do(samples) ) { framesRead++; procWriter.Do(samples); } procReader.Stop(); procWriter.Stop(); // Once written to disk, now we recover it, and // check it is the same frame by frame CLAM::MultiChannelAudioFileReader procReader2; cfgReader.SetSourceFile( "test-mp3-HighVBR-44.wav" ); CPPUNIT_ASSERT_EQUAL( true, procReader2.Configure( cfgReader ) ); std::vector samples2(2); samples2[0].SetSize( 4096 ); samples2[1].SetSize( 4096 ); procReader.Start(); procReader2.Start(); int framesChecked = 0; double maxSimLeft = -1e20; int maxSimLeftFrame = 0; double minSimLeft = 1e20; int minSimLeftFrame = 0; double averageSimLeft = 0.0; double maxSimRight = -1e20; int maxSimRightFrame = 0; double minSimRight = 1e20; int minSimRightFrame = 0; double averageSimRight = 0.0; while( procReader.Do(samples) && procReader2.Do(samples2) ) { framesChecked++; double simLeft = evaluateSimilarity( samples[0].GetBuffer(), samples2[0].GetBuffer() ); double simRight = evaluateSimilarity( samples[1].GetBuffer(), samples2[1].GetBuffer() ); if ( simLeft > maxSimLeft ) { maxSimLeft = simLeft; maxSimLeftFrame = framesChecked; } if ( simLeft < minSimLeft ) { minSimLeft = simLeft; minSimLeftFrame = framesChecked; } averageSimLeft += simLeft; if ( simRight > maxSimRight ) { maxSimRight = simRight; maxSimRightFrame = framesChecked; } if ( simRight < minSimRight ) { minSimRight = simRight; minSimRightFrame = framesChecked; } averageSimRight += simRight; CPPUNIT_ASSERT ( simLeft >= 0.9 ); CPPUNIT_ASSERT ( simRight >= 0.9 ); } procReader.Stop(); procReader2.Stop(); averageSimLeft *= (1.0/double(framesChecked)); averageSimRight *= (1.0/double(framesChecked)); /* std::cout << std::endl; std::cout << "Mp3 - HighVBR" << std::endl; std::cout << "Maximum Left similarity: " << maxSimLeft << " at " << maxSimLeftFrame; std::cout << std::endl; std::cout << "Minimum Left similarity: " << minSimLeft << " at " << minSimLeftFrame; std::cout << std::endl; std::cout << "Average Left similarity: " << averageSimLeft << std::endl; std::cout << std::endl; std::cout << "Maximum Right similarity: " << maxSimRight << " at " << maxSimRightFrame; std::cout << std::endl; std::cout << "Minimum Right similarity: " << minSimRight << " at " << minSimRightFrame; std::cout << std::endl; std::cout << "Average Right similarity: " << averageSimRight << std::endl; */ CPPUNIT_ASSERT_EQUAL( framesRead, framesChecked ); } void test_MpegAudioFiles_AvgVBR_44kHz_AreDecoded_OK() { CLAM::MultiChannelAudioFileReaderConfig cfgReader; cfgReader.SetSourceFile( mPathToTestData+"test-stereo-decoding-AvgVBR_44.mp3" ); CLAM::MultiChannelAudioFileReader procReader(cfgReader); CLAM::MultiChannelAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "test-mp3-AvgVBR-44.wav" ); cfgWriter.SetSampleRate( procReader.GetHeader().GetSampleRate() ); cfgWriter.SetNChannels( procReader.GetHeader().GetChannels() ); CLAM::MultiChannelAudioFileWriter procWriter(cfgWriter); std::vector samples(2); samples[0].SetSize( 4096 ); samples[1].SetSize( 4096 ); procReader.Start(); procWriter.Start(); CLAM::TSize framesRead = 0; while( procReader.Do(samples) ) { framesRead++; procWriter.Do(samples); } procReader.Stop(); procWriter.Stop(); // Once written to disk, now we recover it, and // check it is the same frame by frame CLAM::MultiChannelAudioFileReader procReader2; cfgReader.SetSourceFile( "test-mp3-AvgVBR-44.wav" ); CPPUNIT_ASSERT_EQUAL( true, procReader2.Configure( cfgReader ) ); std::vector samples2(2); samples2[0].SetSize( 4096 ); samples2[1].SetSize( 4096 ); procReader.Start(); procReader2.Start(); int framesChecked = 0; double maxSimLeft = -1e20; int maxSimLeftFrame = 0; double minSimLeft = 1e20; int minSimLeftFrame = 0; double averageSimLeft = 0.0; double maxSimRight = -1e20; int maxSimRightFrame = 0; double minSimRight = 1e20; int minSimRightFrame = 0; double averageSimRight = 0.0; while( procReader.Do(samples) && procReader2.Do(samples2) ) { framesChecked++; double simLeft = evaluateSimilarity( samples[0].GetBuffer(), samples2[0].GetBuffer() ); double simRight = evaluateSimilarity( samples[1].GetBuffer(), samples2[1].GetBuffer() ); if ( simLeft > maxSimLeft ) { maxSimLeft = simLeft; maxSimLeftFrame = framesChecked; } if ( simLeft < minSimLeft ) { minSimLeft = simLeft; minSimLeftFrame = framesChecked; } averageSimLeft += simLeft; if ( simRight > maxSimRight ) { maxSimRight = simRight; maxSimRightFrame = framesChecked; } if ( simRight < minSimRight ) { minSimRight = simRight; minSimRightFrame = framesChecked; } averageSimRight += simRight; CPPUNIT_ASSERT ( simLeft >= 0.9 ); CPPUNIT_ASSERT ( simRight >= 0.9 ); } procReader.Stop(); procReader2.Stop(); averageSimLeft *= (1.0/double(framesChecked)); averageSimRight *= (1.0/double(framesChecked)); /* std::cout << std::endl; std::cout << "Mp3 - AvgVBR" << std::endl; std::cout << "Maximum Left similarity: " << maxSimLeft << " at " << maxSimLeftFrame; std::cout << std::endl; std::cout << "Minimum Left similarity: " << minSimLeft << " at " << minSimLeftFrame; std::cout << std::endl; std::cout << "Average Left similarity: " << averageSimLeft << std::endl; std::cout << std::endl; std::cout << "Maximum Right similarity: " << maxSimRight << " at " << maxSimRightFrame; std::cout << std::endl; std::cout << "Minimum Right similarity: " << minSimRight << " at " << minSimRightFrame; std::cout << std::endl; std::cout << "Average Right similarity: " << averageSimRight << std::endl; */ CPPUNIT_ASSERT_EQUAL( framesRead, framesChecked ); } }; } clam-1.4.0/test/FunctionalTests/ProcessingTests/TestOnsetDetector.cxx0000644000000000000000000005021410157301210024527 0ustar rootroot#include #include "cppUnitHelper.hxx" // necessary for the custom assert #include "RhythmDescriptionHelpers.hxx" #include "XMLStorage.hxx" #include "OnsetDetector.hxx" #include "Normalization.hxx" #include "AudioFile.hxx" #include "MonoAudioFileReader.hxx" #include "AubioOnsetDetector.hxx" namespace CLAMTest { class TestOnsetDetector; CPPUNIT_TEST_SUITE_REGISTRATION( TestOnsetDetector ); class TestOnsetDetector : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( TestOnsetDetector ); CPPUNIT_TEST( test_02_alles_Onsets ); CPPUNIT_TEST( test_12_cubic_Onsets ); CPPUNIT_TEST( test_ALoCubano_Onsets ); CPPUNIT_TEST( test_AmourEnPoudre_Onsets ); CPPUNIT_TEST( test_Amsterdam_Onsets ); CPPUNIT_TEST( test_blue_monday_Onsets ); CPPUNIT_TEST( test_clicseq_Onsets ); CPPUNIT_TEST( test_drums_electronic_guit_Onsets ); CPPUNIT_TEST( test_elecpiano_drums_Onsets ); CPPUNIT_TEST( test_test1_Onsets ); CPPUNIT_TEST( test_test2_Onsets ); CPPUNIT_TEST( test_test_Onsets ); CPPUNIT_TEST_SUITE_END(); protected: std::string mPathToTests; CLAM::TData mAudioSampleRate; public: void setUp() { mPathToTests = "../../../../../CLAM-TestData/RhythmDescription"; } void tearDown() { } void LoadAudio( CLAM::Audio& audio, const std::string& audioFileName ) { CLAM::AudioFile file; file.OpenExisting( audioFileName ); if ( !file.IsReadable() ) { throw CLAM::Err( "Could not open file!" ); } CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( file ); CLAM::MonoAudioFileReader reader; reader.Configure( cfg ); CLAM::TSize fileSize = file.GetHeader().GetSamples(); audio.SetSize(fileSize); audio.SetSampleRate(file.GetHeader().GetSampleRate()); //Read Audio File reader.Start(); reader.Do(audio); reader.Stop(); mAudioSampleRate = audio.GetSampleRate(); } void ExtractOnsetsSequence( std::string filename, CLAM::Array< CLAM::TimeIndex >& transients ) { CLAM::Audio readAudio; LoadAudio( readAudio, filename ); CLAM::TData sampleRate = readAudio.GetSampleRate(); float duration=readAudio.GetSize()/sampleRate; /* CLAM::RhythmDescription::AubioOnsetDetectorConfig odCfg; CLAM::RhythmDescription::AubioOnsetDetector onsetDetector; odCfg.SetMethod( CLAM::RhythmDescription::EODAlgorithms::ePhase ); onsetDetector.Configure( odCfg ); onsetDetector.Start(); onsetDetector.Do( readAudio, transients ); onsetDetector.Stop(); */ CLAM::Segment seg; seg.AddAudio(); seg.UpdateData(); seg.SetHoldsData(true); seg.SetEndTime(duration); seg.GetAudio().SetSize( readAudio.GetSize() ); seg.GetAudio().SetSampleRate( readAudio.GetSampleRate() ); CLAM::NormalizationConfig ncfg; ncfg.SetType( 3 ); // scaling factor computed from "dominant energy" CLAM::Normalization audioNorm; audioNorm.Configure( ncfg ); audioNorm.Start(); audioNorm.Do( readAudio, seg.GetAudio() ); audioNorm.Stop(); CLAM::OnsetDetectorConfig onsetconfig; CLAM::OnsetDetector onset(onsetconfig); onsetconfig.SetComputeOffsets(false); onset.Configure(onsetconfig); onset.Start(); onset.Do(seg, transients); transients.Resize(transients.Size()+1); transients.SetSize(transients.Size()+1); for(int i=transients.Size()-1;i>0;i--) { transients[i].SetPosition(transients[i-1].GetPosition()*sampleRate); transients[i].SetWeight(transients[i-1].GetWeight()); } transients[0].SetPosition(0.0); transients[0].SetWeight(0.0); } private: void test_02_alles_Onsets() { RhythmDescriptionTests::TransientEventList inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Onsets/02_alles_Onsets.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Onsets/02_alles_Onsets.xml", inst.IsValid() == true); CLAM::Array< CLAM::TimeIndex > extractedEvents; ExtractOnsetsSequence( mPathToTests + "/" + inst.GetRelativePath(), extractedEvents); RhythmDescriptionTests::TransientEventList res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "DetectedTransients", "02_alles_Onsets.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents(), extractedEvents ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "02_alles_Onsets_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().Size(), extractedEvents.Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check 02_alles_Onsets_diff.xml!", diff.GetMaxTimePositionDeviation()/mAudioSampleRate <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check 02_alles_Onsets_diff.xml", diff.GetMaxWeightDeviation() <= 0.5 ); } void test_12_cubic_Onsets() { RhythmDescriptionTests::TransientEventList inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Onsets/12_cubic_Onsets.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Onsets/12_cubic_Onsets.xml", inst.IsValid() == true ); CLAM::Array< CLAM::TimeIndex > extractedEvents; ExtractOnsetsSequence( mPathToTests + "/" + inst.GetRelativePath(), extractedEvents); RhythmDescriptionTests::TransientEventList res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "DetectedTransients", "12_cubic_Onsets.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents(), extractedEvents ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "12_cubic_Onsets_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().Size(), extractedEvents.Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check 12_cubic_Onsets_diff.xml!", diff.GetMaxTimePositionDeviation()/mAudioSampleRate <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check 12_cubic_Onsets_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); } void test_blue_monday_Onsets() { RhythmDescriptionTests::TransientEventList inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Onsets/blue_monday_Onsets.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Onsets/blue_monday_Onsets.xml", inst.IsValid() == true); CLAM::Array< CLAM::TimeIndex > extractedEvents; ExtractOnsetsSequence( mPathToTests + "/" + inst.GetRelativePath(), extractedEvents); RhythmDescriptionTests::TransientEventList res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "DetectedTransients", "blue_monday_Onsets.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents(), extractedEvents ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "blue_monday_Onsets_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().Size(), extractedEvents.Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check blue_monday_Onsets_diff.xml!", diff.GetMaxTimePositionDeviation()/mAudioSampleRate <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check blue_monday_Onsets_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); } void test_ALoCubano_Onsets() { RhythmDescriptionTests::TransientEventList inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Onsets/ALoCubano_Onsets.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Onsets/ALoCubano_Onsets.xml", inst.IsValid() == true); CLAM::Array< CLAM::TimeIndex > extractedEvents; ExtractOnsetsSequence( mPathToTests + "/" + inst.GetRelativePath(), extractedEvents); RhythmDescriptionTests::TransientEventList res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "DetectedTransients", "ALoCubano_Onsets.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents(), extractedEvents ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "ALoCubano_Onsets_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().Size(), extractedEvents.Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check ALoCubano_Onsets_diff.xml!", diff.GetMaxTimePositionDeviation()/mAudioSampleRate <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check ALoCubano_Onsets_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); } void test_AmourEnPoudre_Onsets() { RhythmDescriptionTests::TransientEventList inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Onsets/AmourEnPoudre_Onsets.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Onsets/AmourEnPoudre_Onsets.xml", inst.IsValid() == true); CLAM::Array< CLAM::TimeIndex > extractedEvents; ExtractOnsetsSequence( mPathToTests + "/" + inst.GetRelativePath(), extractedEvents); RhythmDescriptionTests::TransientEventList res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "DetectedTransients", "AmourEnPoudre_Onsets.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents(), extractedEvents ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "AmourEnPoudre_Onsets_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().Size(), extractedEvents.Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check AmourEnPoudre_Onsets_diff.xml!", diff.GetMaxTimePositionDeviation()/mAudioSampleRate <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check AmourEnPoudre_Onsets_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); } void test_Amsterdam_Onsets() { RhythmDescriptionTests::TransientEventList inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Onsets/Amsterdam_Onsets.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Onsets/Amsterdam_Onsets.xml", inst.IsValid() == true); CLAM::Array< CLAM::TimeIndex > extractedEvents; ExtractOnsetsSequence( mPathToTests + "/" + inst.GetRelativePath(), extractedEvents); RhythmDescriptionTests::TransientEventList res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "DetectedTransients", "Amsterdam_Onsets.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents(), extractedEvents ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "Amsterdam_Onsets_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().Size(), extractedEvents.Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check Amsterdam_Onsets_diff.xml!", diff.GetMaxTimePositionDeviation()/mAudioSampleRate <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check Amsterdam_Onsets_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); } void test_clicseq_Onsets() { RhythmDescriptionTests::TransientEventList inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Onsets/clicseq_Onsets.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Onsets/clicseq_Onsets.xml", inst.IsValid() == true); CLAM::Array< CLAM::TimeIndex > extractedEvents; ExtractOnsetsSequence( mPathToTests + "/" + inst.GetRelativePath(), extractedEvents); RhythmDescriptionTests::TransientEventList res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "DetectedTransients", "clicseq_Onsets.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents(), extractedEvents ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "clicseq_Onsets_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().Size(), extractedEvents.Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check clicseq_Onsets_diff.xml!", diff.GetMaxTimePositionDeviation()/mAudioSampleRate <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check clicseq_Onsets_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); } void test_drums_electronic_guit_Onsets() { RhythmDescriptionTests::TransientEventList inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Onsets/drums-electronic-guit_Onsets.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Onsets/drums-electronic-guit_Onsets.xml", inst.IsValid() == true); CLAM::Array< CLAM::TimeIndex > extractedEvents; ExtractOnsetsSequence( mPathToTests + "/" + inst.GetRelativePath(), extractedEvents); RhythmDescriptionTests::TransientEventList res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "DetectedTransients", "drums-electronic-guit_Onsets.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents(), extractedEvents ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "drums-electronic-guit_Onsets_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().Size(), extractedEvents.Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check drums-electronic-guit_Onsets_diff.xml!", diff.GetMaxTimePositionDeviation()/mAudioSampleRate <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check drums-electronic-guit_Onsets_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); } void test_elecpiano_drums_Onsets() { RhythmDescriptionTests::TransientEventList inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Onsets/elecpiano-drums_Onsets.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Onsets/elecpiano-drums_Onsets.xml", inst.IsValid() == true); CLAM::Array< CLAM::TimeIndex > extractedEvents; ExtractOnsetsSequence( mPathToTests + "/" + inst.GetRelativePath(), extractedEvents); RhythmDescriptionTests::TransientEventList res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "DetectedTransients", "elecpiano-drums_Onsets.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents(), extractedEvents ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "elecpiano-drums_Onsets_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().Size(), extractedEvents.Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check elecpiano-drums_Onsets_diff.xml!", diff.GetMaxTimePositionDeviation()/mAudioSampleRate <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check elecpiano-drums_Onsets_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().Size(), extractedEvents.Size() ); } void test_test1_Onsets() { RhythmDescriptionTests::TransientEventList inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Onsets/test1_Onsets.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Onsets/test1_Onsets.xml", inst.IsValid() == true); CLAM::Array< CLAM::TimeIndex > extractedEvents; ExtractOnsetsSequence( mPathToTests + "/" + inst.GetRelativePath(), extractedEvents); RhythmDescriptionTests::TransientEventList res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "DetectedTransients", "test1_Onsets.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents(), extractedEvents ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "test1_Onsets_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().Size(), extractedEvents.Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check test1_Onsets_diff.xml!", diff.GetMaxTimePositionDeviation()/mAudioSampleRate <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check test1_Onsets_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); } void test_test2_Onsets() { RhythmDescriptionTests::TransientEventList inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Onsets/test2_Onsets.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Onsets/test2_Onsets.xml", inst.IsValid() == true); CLAM::Array< CLAM::TimeIndex > extractedEvents; ExtractOnsetsSequence( mPathToTests + "/" + inst.GetRelativePath(), extractedEvents); RhythmDescriptionTests::TransientEventList res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "DetectedTransients", "test2_Onsets.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents(), extractedEvents ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "test2_Onsets_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().Size(), extractedEvents.Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check test2_Onsets_diff.xml!", diff.GetMaxTimePositionDeviation()/mAudioSampleRate <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check test2_Onsets_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); } void test_test_Onsets() { RhythmDescriptionTests::TransientEventList inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Onsets/test_Onsets.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Onsets/test_Onsets.xml", inst.IsValid() == true); CLAM::Array< CLAM::TimeIndex > extractedEvents; ExtractOnsetsSequence( mPathToTests + "/" + inst.GetRelativePath(), extractedEvents); RhythmDescriptionTests::TransientEventList res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "DetectedTransients", "test_Onsets.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents(), extractedEvents ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "test_Onsets_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().Size(), extractedEvents.Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check test_Onsets_diff.xml!", diff.GetMaxTimePositionDeviation()/mAudioSampleRate <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check test_Onsets_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); } }; } clam-1.4.0/test/FunctionalTests/ProcessingTests/README.txt0000644000000000000000000000017707751715520022105 0ustar rootrootFunctional tests of processings. These tests should only involve configuring, feeding and checking the output of a processing. clam-1.4.0/test/FunctionalTests/ProcessingTests/TestMelFilterBank.cxx0000644000000000000000000003146010610720021024425 0ustar rootroot#include #include "cppUnitHelper.hxx" // necessary for the custom assert #include "similarityHelper.hxx" #include "MelFilterBank.hxx" #include "FFT.hxx" #include "DataTypes.hxx" #include #include namespace CLAMTest { class MelFilterBankTest; CPPUNIT_TEST_SUITE_REGISTRATION( MelFilterBankTest ); class MelFilterBankTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( MelFilterBankTest ); CPPUNIT_TEST( test_Configuration ); CPPUNIT_TEST( test_Do_FullRangeFilterBank ); CPPUNIT_TEST( test_Do_SpeechRangeFilterBank ); CPPUNIT_TEST_SUITE_END(); private: // back to back reference objects static CLAM::DataArray mFullRangeExpectedMelValues; static CLAM::DataArray mSpeechRangeExpectedMelValues; static CLAM::Spectrum mFullRangeSpec; static CLAM::Spectrum mSpeechRangeSpec; static bool mBack2BackInit; public: /// Common initialization, executed before each test method void setUp() { if ( !mBack2BackInit ) { mBack2BackInit = true; // Expected Mel filter bank output values setup CLAM::TData fullRangeValues[] = { 8402.759, 5593.134, 1945.569, 1437.992, 1166.799, 1021.579, 852.393, 811.837, 718.220, 636.031, 704.546, 918.747, 965.266, 942.982, 1237.408, 1801.851, 1749.460, 2328.939, 2832.841, 2376.607 }; mFullRangeExpectedMelValues.Resize( 20 ); mFullRangeExpectedMelValues.SetSize( 20 ); std::copy( fullRangeValues, fullRangeValues + 20, mFullRangeExpectedMelValues.GetPtr() ); CLAM::TData speechRangeValues[] = { 0.000, 80.481, 1297.095, 82.991, 902.328, 275.889, 531.991, 510.485, 338.979, 373.507, 445.152, 342.516, 290.438, 320.306, 374.704, 286.708, 317.216, 216.559, 298.209, 277.066 }; mSpeechRangeExpectedMelValues.Resize( 20 ); mSpeechRangeExpectedMelValues.SetSize( 20 ); std::copy( speechRangeValues, speechRangeValues + 20, mSpeechRangeExpectedMelValues.GetPtr() ); // Input spectrums setup CLAM::SpecTypeFlags specFlags; specFlags.bMagPhase = 1; mFullRangeSpec.SetType(specFlags); mFullRangeSpec.SetSize(128); mFullRangeSpec.SetSpectralRange(22050); CLAM::DataArray& fullRangeMags = mFullRangeSpec.GetMagBuffer(); fullRangeMags[0] = 3863.799805; fullRangeMags[1] = 12563.685547; fullRangeMags[2] = 2473.863037; fullRangeMags[3] = 1377.575806; fullRangeMags[4] = 985.318970; fullRangeMags[5] = 807.879456; fullRangeMags[6] = 653.121704; fullRangeMags[7] = 530.926941; fullRangeMags[8] = 484.075195; fullRangeMags[9] = 383.188141; fullRangeMags[10] = 314.185913; fullRangeMags[11] = 331.607544; fullRangeMags[12] = 367.209595; fullRangeMags[13] = 218.948563; fullRangeMags[14] = 274.610565; fullRangeMags[15] = 159.711609; fullRangeMags[16] = 197.033371; fullRangeMags[17] = 237.351715; fullRangeMags[18] = 177.763138; fullRangeMags[19] = 145.425201; fullRangeMags[20] = 44.067760; fullRangeMags[21] = 305.115448; fullRangeMags[22] = 151.477142; fullRangeMags[23] = 147.398636; fullRangeMags[24] = 97.936569; fullRangeMags[25] = 254.275620; fullRangeMags[26] = 252.690063; fullRangeMags[27] = 104.618202; fullRangeMags[28] = 238.678238; fullRangeMags[29] = 238.413589; fullRangeMags[30] = 106.487411; fullRangeMags[31] = 157.417999; fullRangeMags[32] = 196.605453; fullRangeMags[33] = 156.383759; fullRangeMags[34] = 195.228119; fullRangeMags[35] = 66.575058; fullRangeMags[36] = 80.477692; fullRangeMags[37] = 128.186066; fullRangeMags[38] = 155.196106; fullRangeMags[39] = 164.427521; fullRangeMags[40] = 186.805405; fullRangeMags[41] = 125.127724; fullRangeMags[42] = 109.505936; fullRangeMags[43] = 163.726730; fullRangeMags[44] = 149.201904; fullRangeMags[45] = 112.674171; fullRangeMags[46] = 103.977386; fullRangeMags[47] = 300.834686; fullRangeMags[48] = 161.853104; fullRangeMags[49] = 142.473419; fullRangeMags[50] = 255.723755; fullRangeMags[51] = 36.553200; fullRangeMags[52] = 41.701927; fullRangeMags[53] = 274.056519; fullRangeMags[54] = 336.059143; fullRangeMags[55] = 243.904984; fullRangeMags[56] = 184.314789; fullRangeMags[57] = 197.449814; fullRangeMags[58] = 85.940903; fullRangeMags[59] = 296.949280; fullRangeMags[60] = 131.487427; fullRangeMags[61] = 112.573540; fullRangeMags[62] = 204.185013; fullRangeMags[63] = 76.627083; fullRangeMags[64] = 168.378326; fullRangeMags[65] = 105.379623; fullRangeMags[66] = 101.306183; fullRangeMags[67] = 108.629196; fullRangeMags[68] = 95.293953; fullRangeMags[69] = 155.516388; fullRangeMags[70] = 253.814713; fullRangeMags[71] = 272.925171; fullRangeMags[72] = 252.411789; fullRangeMags[73] = 182.065308; fullRangeMags[74] = 146.791016; fullRangeMags[75] = 201.107864; fullRangeMags[76] = 65.739845; fullRangeMags[77] = 126.323753; fullRangeMags[78] = 145.190552; fullRangeMags[79] = 97.506729; fullRangeMags[80] = 126.490814; fullRangeMags[81] = 351.613800; fullRangeMags[82] = 179.530670; fullRangeMags[83] = 261.162109; fullRangeMags[84] = 95.853531; fullRangeMags[85] = 291.796692; fullRangeMags[86] = 256.122589; fullRangeMags[87] = 181.163788; fullRangeMags[88] = 140.050858; fullRangeMags[89] = 254.090790; fullRangeMags[90] = 129.594788; fullRangeMags[91] = 111.446365; fullRangeMags[92] = 295.206085; fullRangeMags[93] = 151.116455; fullRangeMags[94] = 266.566742; fullRangeMags[95] = 27.534611; fullRangeMags[96] = 51.423008; fullRangeMags[97] = 229.461517; fullRangeMags[98] = 272.580170; fullRangeMags[99] = 165.507751; fullRangeMags[100] = 42.286980; fullRangeMags[101] = 125.545723; fullRangeMags[102] = 120.389374; fullRangeMags[103] = 257.682861; fullRangeMags[104] = 189.390701; fullRangeMags[105] = 107.361794; fullRangeMags[106] = 315.615295; fullRangeMags[107] = 146.639496; fullRangeMags[108] = 22.579048; fullRangeMags[109] = 112.955009; fullRangeMags[110] = 175.849106; fullRangeMags[111] = 140.709534; fullRangeMags[112] = 65.522446; fullRangeMags[113] = 94.679405; fullRangeMags[114] = 75.674004; fullRangeMags[115] = 76.928978; fullRangeMags[116] = 73.280907; fullRangeMags[117] = 76.281586; fullRangeMags[118] = 81.804390; fullRangeMags[119] = 76.965645; fullRangeMags[120] = 71.684120; fullRangeMags[121] = 65.579536; fullRangeMags[122] = 77.021393; fullRangeMags[123] = 75.680740; fullRangeMags[124] = 79.639420; fullRangeMags[125] = 81.398521; fullRangeMags[126] = 70.366844; fullRangeMags[127] = 67.170120; mSpeechRangeSpec.SetType(specFlags); mSpeechRangeSpec.SetSize(128); mSpeechRangeSpec.SetSpectralRange(22050); CLAM::DataArray& speechMags = mSpeechRangeSpec.GetMagBuffer(); speechMags[0] = 3863.799805; speechMags[1] = 12563.685547; speechMags[2] = 2473.863037; speechMags[3] = 1377.575806; speechMags[4] = 985.318970; speechMags[5] = 807.879456; speechMags[6] = 653.121704; speechMags[7] = 530.926941; speechMags[8] = 484.075195; speechMags[9] = 383.188141; speechMags[10] = 314.185913; speechMags[11] = 331.607544; speechMags[12] = 367.209595; speechMags[13] = 218.948563; speechMags[14] = 274.610565; speechMags[15] = 159.711609; speechMags[16] = 197.033371; speechMags[17] = 237.351715; speechMags[18] = 177.763138; speechMags[19] = 145.425201; speechMags[20] = 44.067760; speechMags[21] = 305.115448; speechMags[22] = 151.477142; speechMags[23] = 147.398636; speechMags[24] = 97.936569; speechMags[25] = 254.275620; speechMags[26] = 252.690063; speechMags[27] = 104.618202; speechMags[28] = 238.678238; speechMags[29] = 238.413589; speechMags[30] = 106.487411; speechMags[31] = 157.417999; speechMags[32] = 196.605453; speechMags[33] = 156.383759; speechMags[34] = 195.228119; speechMags[35] = 66.575058; speechMags[36] = 80.477692; speechMags[37] = 128.186066; speechMags[38] = 155.196106; speechMags[39] = 164.427521; speechMags[40] = 186.805405; speechMags[41] = 125.127724; speechMags[42] = 109.505936; speechMags[43] = 163.726730; speechMags[44] = 149.201904; speechMags[45] = 112.674171; speechMags[46] = 103.977386; speechMags[47] = 300.834686; speechMags[48] = 161.853104; speechMags[49] = 142.473419; speechMags[50] = 255.723755; speechMags[51] = 36.553200; speechMags[52] = 41.701927; speechMags[53] = 274.056519; speechMags[54] = 336.059143; speechMags[55] = 243.904984; speechMags[56] = 184.314789; speechMags[57] = 197.449814; speechMags[58] = 85.940903; speechMags[59] = 296.949280; speechMags[60] = 131.487427; speechMags[61] = 112.573540; speechMags[62] = 204.185013; speechMags[63] = 76.627083; speechMags[64] = 168.378326; speechMags[65] = 105.379623; speechMags[66] = 101.306183; speechMags[67] = 108.629196; speechMags[68] = 95.293953; speechMags[69] = 155.516388; speechMags[70] = 253.814713; speechMags[71] = 272.925171; speechMags[72] = 252.411789; speechMags[73] = 182.065308; speechMags[74] = 146.791016; speechMags[75] = 201.107864; speechMags[76] = 65.739845; speechMags[77] = 126.323753; speechMags[78] = 145.190552; speechMags[79] = 97.506729; speechMags[80] = 126.490814; speechMags[81] = 351.613800; speechMags[82] = 179.530670; speechMags[83] = 261.162109; speechMags[84] = 95.853531; speechMags[85] = 291.796692; speechMags[86] = 256.122589; speechMags[87] = 181.163788; speechMags[88] = 140.050858; speechMags[89] = 254.090790; speechMags[90] = 129.594788; speechMags[91] = 111.446365; speechMags[92] = 295.206085; speechMags[93] = 151.116455; speechMags[94] = 266.566742; speechMags[95] = 27.534611; speechMags[96] = 51.423008; speechMags[97] = 229.461517; speechMags[98] = 272.580170; speechMags[99] = 165.507751; speechMags[100] = 42.286980; speechMags[101] = 125.545723; speechMags[102] = 120.389374; speechMags[103] = 257.682861; speechMags[104] = 189.390701; speechMags[105] = 107.361794; speechMags[106] = 315.615295; speechMags[107] = 146.639496; speechMags[108] = 22.579048; speechMags[109] = 112.955009; speechMags[110] = 175.849106; speechMags[111] = 140.709534; speechMags[112] = 65.522446; speechMags[113] = 94.679405; speechMags[114] = 75.674004; speechMags[115] = 76.928978; speechMags[116] = 73.280907; speechMags[117] = 76.281586; speechMags[118] = 81.804390; speechMags[119] = 76.965645; speechMags[120] = 71.684120; speechMags[121] = 65.579536; speechMags[122] = 77.021393; speechMags[123] = 75.680740; speechMags[124] = 79.639420; speechMags[125] = 81.398521; speechMags[126] = 70.366844; speechMags[127] = 67.170120; } } /// Common clean up, executed after each test method void tearDown() { } private: void test_Configuration() { CLAM::MelFilterBankConfig mfbConfig; mfbConfig.SetSpectrumSize(256); mfbConfig.SetSpectralRange(22050); mfbConfig.SetLowCutoff(300); mfbConfig.SetHighCutoff(3400); mfbConfig.SetNumBands(20); CLAM::MelFilterBank proc; CPPUNIT_ASSERT_EQUAL( true, proc.Configure( mfbConfig ) ); } void test_Do_FullRangeFilterBank() { CLAM::MelFilterBankConfig mfbConfig; mfbConfig.SetSpectrumSize( mFullRangeSpec.GetSize()); mfbConfig.SetSpectralRange(mFullRangeSpec.GetSpectralRange()); mfbConfig.SetLowCutoff(0); mfbConfig.SetHighCutoff(22050); mfbConfig.SetNumBands(20); CLAM::MelSpectrum melSpec; CLAM::MelFilterBank proc; proc.Configure( mfbConfig ); proc.Start( ); proc.Do( mFullRangeSpec, melSpec ); proc.Stop(); double sim = evaluateSimilarity( mFullRangeExpectedMelValues, melSpec.GetCoefficients() ); /* std::cout << sim; std::cout.flush(); */ CPPUNIT_ASSERT( sim >= 0.999 ); } void test_Do_SpeechRangeFilterBank() { CLAM::MelFilterBankConfig mfbConfig; mfbConfig.SetSpectrumSize(mSpeechRangeSpec.GetSize()); mfbConfig.SetSpectralRange(mSpeechRangeSpec.GetSpectralRange()); mfbConfig.SetLowCutoff(300); mfbConfig.SetHighCutoff(3400); mfbConfig.SetNumBands(20); CLAM::MelSpectrum melSpec; CLAM::MelFilterBank proc; proc.Configure( mfbConfig ); proc.Start(); proc.Do( mSpeechRangeSpec, melSpec ); proc.Stop(); double sim = evaluateSimilarity( mSpeechRangeExpectedMelValues, melSpec.GetCoefficients() ); /* std::cout << sim; std::cout.flush(); */ CPPUNIT_ASSERT( sim >= 0.999 ); } }; CLAM::DataArray MelFilterBankTest::mFullRangeExpectedMelValues; CLAM::DataArray MelFilterBankTest::mSpeechRangeExpectedMelValues; CLAM::Spectrum MelFilterBankTest::mFullRangeSpec; CLAM::Spectrum MelFilterBankTest::mSpeechRangeSpec; bool MelFilterBankTest::mBack2BackInit = false; } // namespace CLAMTest clam-1.4.0/test/FunctionalTests/ProcessingTests/TestIFFT.cxx0000644000000000000000000001103210625072330022500 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "similarityHelper.hxx" #include "XMLStorage.hxx" #ifdef USE_FFTW #include "IFFT_rfftw.hxx" namespace CLAMTest { class IFFTFunctionalTest; CPPUNIT_TEST_SUITE_REGISTRATION( IFFTFunctionalTest ); class IFFTFunctionalTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( IFFTFunctionalTest ); CPPUNIT_TEST( test_FFTW_WithPowerOfTwoSignalSpectrum ); CPPUNIT_TEST( test_FFTW_WithNonPowerOfTwoSignalSpectrum ); CPPUNIT_TEST_SUITE_END(); protected: static double smEqualityThreshold; static bool smBack2BackDataLoaded; static CLAM::Spectrum smReferenceP2Spectrum; static CLAM::Spectrum smReferenceNP2Spectrum; std::string mPathToTestData; protected: // Auxiliary methods void setupSine_F0400Hz_SR8kHz_1024samples( CLAM::Audio& object ) { const CLAM::TSize samples = 1024; const CLAM::TSize sampleRate = 8000; const CLAM::TData sineFreq = 400.0f; object.SetSize( samples ); object.SetSampleRate( sampleRate ); object.SetBeginTime( CLAM::TTime(0.0) ); object.SetEndTime( (CLAM::TTime(samples)/CLAM::TTime(sampleRate))*1000. ); for ( CLAM::TSize i=0; iAttach( smReferenceP2Spectrum ); //(*processing.GetOutPorts().Begin())->Attach( actualOutput ); processing.Start(); processing.Do( smReferenceP2Spectrum, actualOutput ); processing.Stop(); double similarity = evaluateSimilarity( expectedOutput.GetBuffer(), actualOutput.GetBuffer() ); CPPUNIT_ASSERT( smEqualityThreshold <= similarity ); } void test_FFTW_WithNonPowerOfTwoSignalSpectrum() { // The signal that should be CLAM::Audio expectedOutput; // The signal synthesized by the IFFT processing CLAM::Audio actualOutput; setupSine_F0400Hz_SR8kHz_884samples( expectedOutput ); actualOutput.SetSize( expectedOutput.GetSize() ); actualOutput.SetSampleRate( expectedOutput.GetSampleRate() ); CLAM::IFFTConfig processingConfig; CLAM::IFFT_rfftw processing; processingConfig.SetAudioSize( expectedOutput.GetSize() ); processing.Configure( processingConfig ); //(*processing.GetInPorts().Begin())->Attach( smReferenceNP2Spectrum ); //(*processing.GetOutPorts().Begin())->Attach( actualOutput ); processing.Start(); processing.Do( smReferenceNP2Spectrum, actualOutput ); processing.Stop(); double similarity = evaluateSimilarity( expectedOutput.GetBuffer(), actualOutput.GetBuffer() ); CPPUNIT_ASSERT( smEqualityThreshold <= similarity ); } }; double IFFTFunctionalTest::smEqualityThreshold = 0.9999; bool IFFTFunctionalTest::smBack2BackDataLoaded = false; CLAM::Spectrum IFFTFunctionalTest::smReferenceP2Spectrum; CLAM::Spectrum IFFTFunctionalTest::smReferenceNP2Spectrum; } #endif clam-1.4.0/test/FunctionalTests/ProcessingTests/TestMultiChannelAudioFileWriter.cxx0000644000000000000000000002106110634462746027333 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "MultiChannelAudioFileReader.hxx" #include "MultiChannelAudioFileWriter.hxx" #include "similarityHelper.hxx" #include "CLAM_Math.hxx" #include "OSDefines.hxx" namespace CLAMTest { class MultiChannelAudioFileWriterFunctionalTest; CPPUNIT_TEST_SUITE_REGISTRATION( MultiChannelAudioFileWriterFunctionalTest ); class MultiChannelAudioFileWriterFunctionalTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( MultiChannelAudioFileWriterFunctionalTest ); CPPUNIT_TEST( testDo_PCM_WritesRightAKnownSignal ); CPPUNIT_TEST( testDo_DoubleWriting_Is_Not_Allowed ); CPPUNIT_TEST( testDo_PCM_WritesTheSameThatWasRead ); CPPUNIT_TEST( testDo_OggVorbis_WritesTheSameThatWasRead ); CPPUNIT_TEST_SUITE_END(); protected: std::string mPathToTestData; public: void setUp() { mPathToTestData = GetTestDataDirectory(); } void tearDown() { } private: void testDo_PCM_WritesRightAKnownSignal() { CLAM::MultiChannelAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "twosines-stereo.wav" ); CLAM::MultiChannelAudioFileWriter procWriter(cfgWriter); CPPUNIT_ASSERT_EQUAL( true, procWriter.Configure( cfgWriter ) ); std::vector samples(2); samples[0].SetSize( 256 ); samples[1].SetSize( 256 ); procWriter.Start(); int framesSynth = 0; CLAM::TData srate = 44100.; CLAM::TData f0 = 100; CLAM::TData f1 = 400; while ( framesSynth < 100 ) { for ( int i = 0; i < 256; i++ ) { samples[0].GetBuffer()[i] = 0.0; samples[1].GetBuffer()[i] = 0.0; } procWriter.Do(samples); framesSynth++; } // cosinus starts at zero ( -pi/2 intial phase ) CLAM::TData phi0 = -M_PI / 2.0; CLAM::TData phi1 = -M_PI / 2.0; CLAM::TData dphi0 = (2.0*M_PI*f0) / srate; CLAM::TData dphi1 = (2.0*M_PI*f1) / srate; while( framesSynth < 200 ) { for ( int i = 0; i < 256; i++ ) { samples[0].GetBuffer()[i] = 0.5 * cos( phi0 ); samples[1].GetBuffer()[i] = 0.5 * cos( phi1 ); phi0 += dphi0; phi1 += dphi1; } procWriter.Do(samples); framesSynth++; } procWriter.Stop(); } void testDo_DoubleWriting_Is_Not_Allowed() { CLAM::MultiChannelAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "twosines-stereo.wav" ); CLAM::MultiChannelAudioFileWriter procWriter; CLAM::MultiChannelAudioFileWriter procWriter2; procWriter.Configure( cfgWriter ); CPPUNIT_ASSERT_EQUAL( false, procWriter2.Configure( cfgWriter ) ); } void testDo_PCM_WritesTheSameThatWasRead() { CLAM::MultiChannelAudioFileReaderConfig cfgReader; cfgReader.SetSourceFile( mPathToTestData+"test-stereo-decoding.wav" ); CLAM::MultiChannelAudioFileReader procReader(cfgReader); CLAM::MultiChannelAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "test-stereo-decoding-copy.wav" ); cfgWriter.SetNChannels( procReader.GetHeader().GetChannels() ); cfgWriter.SetSampleRate( procReader.GetHeader().GetSampleRate() ); // Not yet supported // cfgWriter.SetFormat( procReader.GetHeader().GetFormat() ); // cfgWriter.SetEncoding( procReader.GetHeader().GetEncoding() ); // cfgWriter.SetEndianess( procReader.GetHeader().GetEndianess() ); CLAM::MultiChannelAudioFileWriter procWriter; CPPUNIT_ASSERT_EQUAL( true, procWriter.Configure( cfgWriter ) ); std::vector samples(2); samples[0].SetSize( 256 ); samples[1].SetSize( 256 ); procReader.Start(); procWriter.Start(); int framesRead = 0; while( procReader.Do(samples) ) { framesRead++; procWriter.Do(samples); } procReader.Stop(); procWriter.Stop(); // Once written to disk, now we recover it, and // check it is the same frame by frame CLAM::MultiChannelAudioFileReader procReader2; cfgReader.SetSourceFile( "test-stereo-decoding-copy.wav" ); CPPUNIT_ASSERT_EQUAL( true, procReader2.Configure( cfgReader ) ); std::vector samples2(2); samples2[0].SetSize( 256 ); samples2[1].SetSize( 256 ); procReader.Start(); procReader2.Start(); int framesChecked = 0; while( procReader.Do(samples) && procReader2.Do(samples2) ) { framesChecked++; double simLeft = evaluateSimilarity( samples[0].GetBuffer(), samples2[0].GetBuffer() ); CPPUNIT_ASSERT ( simLeft >= 0.9999 ); double simRight = evaluateSimilarity( samples[1].GetBuffer(), samples2[1].GetBuffer() ); CPPUNIT_ASSERT ( simRight >= 0.9999 ); } procReader.Stop(); procReader2.Stop(); CPPUNIT_ASSERT_EQUAL( framesRead, framesChecked ); } void testDo_OggVorbis_WritesTheSameThatWasRead() { CLAM::MultiChannelAudioFileReaderConfig cfgReader; cfgReader.SetSourceFile( mPathToTestData+"ElvisStereo.wav" ); CLAM::MultiChannelAudioFileReader procReader; CPPUNIT_ASSERT_EQUAL( true, procReader.Configure( cfgReader ) ); CLAM::MultiChannelAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "ElvisStereo-copy.ogg" ); cfgWriter.SetSampleRate( procReader.GetHeader().GetSampleRate()); cfgWriter.SetNChannels( procReader.GetHeader().GetChannels()); CLAM::MultiChannelAudioFileWriter procWriter; CPPUNIT_ASSERT_EQUAL( true, procWriter.Configure( cfgWriter ) ); std::vector samples(2); samples[0].SetSize( 4096 ); samples[1].SetSize( 4096 ); procReader.Start(); procWriter.Start(); CLAM::TSize framesRead = 0; while( procReader.Do(samples) ) { framesRead++; procWriter.Do(samples); } procReader.Stop(); procWriter.Stop(); // Once written to disk, now we recover it, and // check it is the same frame by frame CLAM::MultiChannelAudioFileReader procReader2; cfgReader.SetSourceFile( "ElvisStereo-copy.ogg" ); CPPUNIT_ASSERT_EQUAL( true, procReader2.Configure( cfgReader ) ); std::vector samples2(2); samples2[0].SetSize( 4096 ); samples2[1].SetSize( 4096 ); procReader.Start(); procReader2.Start(); int framesChecked = 0; double maxSimLeft = -1e20; int maxSimLeftFrame = 0; double minSimLeft = 1e20; int minSimLeftFrame = 0; double averageSimLeft = 0.0; double maxSimRight = -1e20; int maxSimRightFrame = 0; double minSimRight = 1e20; int minSimRightFrame = 0; double averageSimRight = 0.0; while( procReader.Do(samples) && procReader2.Do(samples2) ) { framesChecked++; double simLeft = evaluateSimilarity( samples[0].GetBuffer(), samples2[0].GetBuffer() ); double simRight = evaluateSimilarity( samples[1].GetBuffer(), samples2[1].GetBuffer() ); if ( simLeft > maxSimLeft ) { maxSimLeft = simLeft; maxSimLeftFrame = framesChecked; } if ( simLeft < minSimLeft ) { minSimLeft = simLeft; minSimLeftFrame = framesChecked; } averageSimLeft += simLeft; if ( simRight > maxSimRight ) { maxSimRight = simRight; maxSimRightFrame = framesChecked; } if ( simRight < minSimRight ) { minSimRight = simRight; minSimRightFrame = framesChecked; } averageSimRight += simRight; CPPUNIT_ASSERT ( simLeft >= 0.9 ); CPPUNIT_ASSERT ( simRight >= 0.9 ); } procReader.Stop(); procReader2.Stop(); averageSimLeft *= (1.0/double(framesChecked)); averageSimRight *= (1.0/double(framesChecked)); /* std::cout << std::endl; std::cout << "test_Do_OggVorbis" << std::endl; std::cout << "Maximum Left similarity: " << maxSimLeft << " at " << maxSimLeftFrame; std::cout << std::endl; std::cout << "Minimum Left similarity: " << minSimLeft << " at " << minSimLeftFrame; std::cout << std::endl; std::cout << "Average Left similarity: " << averageSimLeft << std::endl; std::cout << "Maximum Right similarity: " << maxSimRight << " at " << maxSimRightFrame; std::cout << std::endl; std::cout << "Minimum Right similarity: " << minSimRight << " at " << minSimRightFrame; std::cout << std::endl; std::cout << "Average Right similarity: " << averageSimRight << std::endl; */ CPPUNIT_ASSERT( fabs( maxSimLeft - 0.999595) < 1e-2 ); CPPUNIT_ASSERT( fabs( minSimLeft - 0.980736) < 1e-2 ); CPPUNIT_ASSERT( fabs( averageSimLeft - 0.99788 ) < 1e-2 ); CPPUNIT_ASSERT( fabs( maxSimRight - 0.999595) < 1e-2 ); CPPUNIT_ASSERT( fabs( minSimRight - 0.980736) < 1e-2 ); CPPUNIT_ASSERT( fabs( averageSimRight - 0.997888) < 1e-2 ); CPPUNIT_ASSERT_EQUAL( framesRead, framesChecked ); } }; } clam-1.4.0/test/FunctionalTests/ProcessingTests/TestMonoAudioFileReader.cxx0000644000000000000000000002546610634462746025623 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "AudioFile.hxx" #include "MonoAudioFileReaderConfig.hxx" #include "MonoAudioFileReader.hxx" #include "MonoAudioFileWriter.hxx" #include "Audio.hxx" #include "CLAM_Math.hxx" #include "AudioFileOpsTestsHelper.hxx" #include "similarityHelper.hxx" #include #include namespace CLAMTest { class MonoAudioFileReaderFunctionalTest; CPPUNIT_TEST_SUITE_REGISTRATION( MonoAudioFileReaderFunctionalTest ); class MonoAudioFileReaderFunctionalTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( MonoAudioFileReaderFunctionalTest ); // Configuration values checking tests CPPUNIT_TEST( testConfigure_ReturnsTrueWithJustFilename ); CPPUNIT_TEST( testConfigure_ReturnsFalseWithoutAudioFileInConfig ); CPPUNIT_TEST( testConfigure_ReturnsTrueWhenFileExists ); CPPUNIT_TEST( testConfigure_ReturnsFalseWhenFileDoesNotExist ); CPPUNIT_TEST( testConfigure_ReturnsTrueWhenSelectedChannelExists ); CPPUNIT_TEST( testConfigure_ReturnsFalseWhenSelectedChannelIsOutOfRange ); // File reading checking CPPUNIT_TEST( testDo_PCM_JustOneFrameFromMonoFile ); CPPUNIT_TEST( testDo_PCM_JustTwoFramesFromMonoFile ); CPPUNIT_TEST( testDo_PCM_JustOneFrameFromStereoFile ); CPPUNIT_TEST( testDo_PCM_JustTwoFramesFromStereoFile ); CPPUNIT_TEST( testDo_OggVorbis_JustOneFrameFromStereoFile ); CPPUNIT_TEST( testDo_OggVorbis_JustTwoFramesFromStereoFile ); CPPUNIT_TEST( test_MpegAudioFiles_AreDecoded_OK ); CPPUNIT_TEST( testDo_JustTwoFramesBeginTimesAreRight ); CPPUNIT_TEST( testDo_JustOneFrame_SampleRateIsOK ); CPPUNIT_TEST( test_WindowsMedia_WAVE_File ); CPPUNIT_TEST_SUITE_END(); protected: // Attributes std::string mPathToTestData; protected: // Auxiliary methods public: // TestFixture interface void setUp() { mPathToTestData = GetTestDataDirectory(); } void tearDown() { } private: // tests cases void testConfigure_ReturnsTrueWithJustFilename() { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"Elvis.wav" ); CLAM::MonoAudioFileReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( true, configResult ); } void testConfigure_ReturnsFalseWithoutAudioFileInConfig() { CLAM::MonoAudioFileReaderConfig cfg; cfg.RemoveSourceFile(); cfg.UpdateData(); CLAM::MonoAudioFileReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( false, configResult ); } void testConfigure_ReturnsTrueWhenFileExists() { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"Elvis.wav" ); CLAM::MonoAudioFileReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( true, configResult ); } void testConfigure_ReturnsFalseWhenFileDoesNotExist() { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"QWERTY.wav" ); CLAM::MonoAudioFileReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( false, configResult ); } void testConfigure_ReturnsTrueWhenSelectedChannelExists() { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"Elvis.wav" ); cfg.SetSelectedChannel( 0 ); CLAM::MonoAudioFileReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( true, configResult ); } void testConfigure_ReturnsFalseWhenSelectedChannelIsOutOfRange() { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"Elvis.wav" ); cfg.SetSelectedChannel( 32768 ); CLAM::MonoAudioFileReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( false, configResult ); } void testDo_PCM_JustOneFrameFromMonoFile() { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"Elvis.wav" ); cfg.SetSelectedChannel( 0 ); CLAM::MonoAudioFileReader proc( cfg ); CLAM::Audio readSamples; readSamples.SetSampleRate( proc.GetHeader().GetSampleRate() ); readSamples.SetSize( 256 ); proc.Start(); proc.Do(readSamples); proc.Stop(); double similarity = fileSimilarity( cfg.GetSourceFile(), 0, readSamples ); CPPUNIT_ASSERT( similarity >= 0.9999 ); } void testDo_PCM_JustTwoFramesFromMonoFile() { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"Elvis.wav" ); cfg.SetSelectedChannel( 0 ); CLAM::MonoAudioFileReader proc( cfg ); CLAM::Audio readSamples_1; readSamples_1.SetSampleRate( proc.GetHeader().GetSampleRate() ); readSamples_1.SetSize( 256 ); CLAM::DataArray previous; previous.Resize( readSamples_1.GetSize() ); previous.SetSize( readSamples_1.GetSize() ); proc.Start(); proc.Do(readSamples_1); std::copy( readSamples_1.GetBuffer().GetPtr(), readSamples_1.GetBuffer().GetPtr()+readSamples_1.GetSize(), previous.GetPtr() ); proc.Do(readSamples_1); proc.Stop(); CPPUNIT_ASSERT( fabs( -0.803968 // MRJ: Value established by inspection - evaluateSimilarity( previous, readSamples_1.GetBuffer()) ) < 1e-4 ); } void testDo_PCM_JustOneFrameFromStereoFile() { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); cfg.SetSelectedChannel( 1 ); CLAM::MonoAudioFileReader proc( cfg ); CLAM::Audio readSamples; readSamples.SetSampleRate( proc.GetHeader().GetSampleRate() ); readSamples.SetSize( 256 ); proc.Start(); proc.Do(readSamples); proc.Stop(); double similarity = fileSimilarity( cfg.GetSourceFile(), 1, readSamples ); CPPUNIT_ASSERT( similarity >= 0.9999 ); } void testDo_PCM_JustTwoFramesFromStereoFile() { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); cfg.SetSelectedChannel( 1 ); CLAM::MonoAudioFileReader proc( cfg ); CLAM::Audio readSamples_1; readSamples_1.SetSampleRate( proc.GetHeader().GetSampleRate() ); readSamples_1.SetSize( 256 ); CLAM::DataArray previous; previous.Resize( readSamples_1.GetSize() ); previous.SetSize( readSamples_1.GetSize() ); proc.Start(); proc.Do(readSamples_1); std::copy( readSamples_1.GetBuffer().GetPtr(), readSamples_1.GetBuffer().GetPtr()+readSamples_1.GetSize(), previous.GetPtr() ); proc.Do(readSamples_1); proc.Stop(); CPPUNIT_ASSERT( evaluateSimilarity( readSamples_1.GetBuffer(), previous ) < 1.0 ); } void testDo_JustTwoFramesBeginTimesAreRight() { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); cfg.SetSelectedChannel( 1 ); CLAM::MonoAudioFileReader proc( cfg ); CLAM::Audio readSamples; readSamples.SetSampleRate( proc.GetHeader().GetSampleRate() ); readSamples.SetSize( 256 ); proc.Start(); proc.Do(readSamples); CLAM::TTime previousBeginTime = readSamples.GetBeginTime(); proc.Do(readSamples); proc.Stop(); CLAM::TTime truth = CLAM::TTime( readSamples.GetSize() ) / proc.GetHeader().GetSampleRate() *1000; CLAM::TTime valueObtained = readSamples.GetBeginTime() - previousBeginTime; CPPUNIT_ASSERT( fabs( truth - valueObtained ) < 1e-4 ); } void testDo_JustOneFrame_SampleRateIsOK() { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"StereoTestFile.wav" ); cfg.SetSelectedChannel( 1 ); CLAM::MonoAudioFileReader proc( cfg ); CLAM::Audio readSamples; readSamples.SetSize( 256 ); proc.Start(); proc.Do(readSamples); proc.Stop(); CPPUNIT_ASSERT_EQUAL( proc.GetHeader().GetSampleRate(), readSamples.GetSampleRate() ); } void testDo_OggVorbis_JustOneFrameFromStereoFile() { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"ElvisStereo.ogg" ); cfg.SetSelectedChannel( 1 ); CLAM::MonoAudioFileReader proc( cfg ); CLAM::Audio readSamples; readSamples.SetSampleRate( proc.GetHeader().GetSampleRate() ); readSamples.SetSize( 256 ); proc.Start(); proc.Do(readSamples); proc.Stop(); double similarity = fileSimilarity( cfg.GetSourceFile(), 1, readSamples ); CPPUNIT_ASSERT( similarity >= 0.9999 ); } void testDo_OggVorbis_JustTwoFramesFromStereoFile() { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( mPathToTestData+"ElvisStereo.ogg" ); cfg.SetSelectedChannel( 1 ); CLAM::MonoAudioFileReader proc( cfg ); CLAM::Audio readSamples_1; readSamples_1.SetSampleRate( proc.GetHeader().GetSampleRate() ); readSamples_1.SetSize( 4096 ); CLAM::DataArray previous; previous.Resize( readSamples_1.GetSize() ); previous.SetSize( readSamples_1.GetSize() ); proc.Start(); for ( int i = 0; i < 10; i++ ) { proc.Do(); std::copy( readSamples_1.GetBuffer().GetPtr(), readSamples_1.GetBuffer().GetPtr()+readSamples_1.GetSize(), previous.GetPtr() ); proc.Do(readSamples_1); } proc.Stop(); double sim = evaluateSimilarity( readSamples_1.GetBuffer(), previous ); CPPUNIT_ASSERT( sim <= 1.0 ); } void test_WindowsMedia_WAVE_File() { CLAM::AudioFileSource file; file.OpenExisting( mPathToTestData + std::string("1-wav-8000.wav" ) ); CPPUNIT_ASSERT_EQUAL( true, file.IsReadable() ); } void test_MpegAudioFiles_AreDecoded_OK() { CLAM::MonoAudioFileReaderConfig cfgReader; cfgReader.SetSourceFile( mPathToTestData+"trumpet.mp3" ); cfgReader.SetSelectedChannel( 0 ); CLAM::MonoAudioFileReader procReader; procReader.Configure( cfgReader ); CLAM::MonoAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "trumpet-copy.wav" ); cfgWriter.SetSampleRate( procReader.GetHeader().GetSampleRate()); CLAM::MonoAudioFileWriter procWriter; procWriter.Configure( cfgWriter ); CLAM::Audio readSamples; readSamples.SetSize( 256 ); procReader.Start(); procWriter.Start(); int framesRead = 0; while( procReader.Do(readSamples) ) { framesRead++; procWriter.Do(readSamples); } procReader.Stop(); procWriter.Stop(); // Once written to disk, now we recover it, and // check it is the same frame by frame CLAM::MonoAudioFileReader procReader2; cfgReader.SetSourceFile( "trumpet-copy.wav" ); CPPUNIT_ASSERT_EQUAL( true, procReader2.Configure( cfgReader ) ); CLAM::Audio readSamples2; readSamples2.SetSize( 256 ); procReader.Start(); procReader2.Start(); int framesChecked = 0; while( procReader.Do(readSamples) && procReader2.Do(readSamples2) ) { double sim = evaluateSimilarity( readSamples.GetBuffer(), readSamples2.GetBuffer() ); framesChecked++; CPPUNIT_ASSERT ( sim >= 0.5 ); } procReader.Stop(); procReader2.Stop(); CPPUNIT_ASSERT_EQUAL(framesRead, framesChecked ); } }; } clam-1.4.0/test/FunctionalTests/ProcessingTests/TestSMSAnalysis.cxx0000644000000000000000000002342610244412424024127 0ustar rootroot #include #include "cppUnitHelper.hxx" #include "AudioFile.hxx" #include "MonoAudioFileReaderConfig.hxx" #include "MonoAudioFileReader.hxx" #include "Audio.hxx" #include "Segment.hxx" #include "XMLStorage.hxx" #include #include #include "SpectralAnalysis.hxx" #include "SpectralAnalysisConfig.hxx" #include "SpectralPeakDetect.hxx" #include "FundFreqDetect.hxx" #include "SinTracking.hxx" #include "SynthSineSpectrum.hxx" #include "SpectrumSubstracter2.hxx" #include "AudioCollator.hxx" // for helperFileExist #include "Spectrum.hxx" #include "SpectrumConfig.hxx" #include "Processing.hxx" #include "SMSAnalysisCore.hxx" #include "SMSAnalysis.hxx" #include "OutPort.hxx" #include "AudioOutPort.hxx" namespace CLAMTest { class SMSAnalysisTest; CPPUNIT_TEST_SUITE_REGISTRATION( SMSAnalysisTest ); class SMSAnalysisTest : public CppUnit::TestFixture { public: CPPUNIT_TEST_SUITE( SMSAnalysisTest ); CPPUNIT_TEST( testPathToFiles ); CPPUNIT_TEST( testSine_comparingSegment); CPPUNIT_TEST( testSweep_comparingSegment ); CPPUNIT_TEST( testTrumpet_comparingSegment ); CPPUNIT_TEST( testSine_innerData ); CPPUNIT_TEST( testSweep_innerData ); CPPUNIT_TEST( testTrumpet_innerData ); CPPUNIT_TEST_SUITE_END(); private: // Attributes CLAM::SMSAnalysisCore mAnalysis; CLAM::SMSAnalysisCore mAnalysis; std::string mPathToTestData; std::string mPathToAnalysisTestData; CLAM::MonoAudioFileReader mReader; void LoadAudioFile( const std::string & audioFileName ) { CLAM::AudioFile file; file.OpenExisting( audioFileName ); CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( file ); mReader.Configure( cfg ); mReader.Start(); CLAM::SMSAnalysisConfig cfgAnalysis; cfgAnalysis.SetSamplingRate( file.GetHeader().GetSampleRate() ); mAnalysis.Stop(); mAnalysis.Configure( cfgAnalysis ); mAnalysis.Start(); } bool CheckResultWithStoredSegment( CLAM::Segment & segment, const std::string fileToLoad ) { std::stringstream streamWithResultOfTest(""); CLAM::XMLStorage::Dump(segment, "Segment", streamWithResultOfTest ); CLAM::Segment inputSegment; CLAM::XMLStorage::Restore( inputSegment, fileToLoad ); std::stringstream streamLoaded(""); CLAM::XMLStorage::Dump( inputSegment, "Segment", streamLoaded ); std::string result( streamWithResultOfTest.str() ); std::string toCheck( streamLoaded.str() ); return (result == toCheck); } std::string StringFromFile( const std::string & nameOfFile ) { std::ifstream file( nameOfFile.c_str() ); return std::string( (std::istreambuf_iterator(file)), std::istreambuf_iterator() ); } std::string StringFromData( CLAM::ProcessingData & data ) { std::stringstream streamWithResultOfTest(""); CLAM::XMLStorage::Dump(data, "Data", streamWithResultOfTest ); return streamWithResultOfTest.str(); } void DoReaderAndAnalysis() { mReader.Do(); mAnalysis.Do(); } public: // TestFixture interface SMSAnalysisTest() { mPathToTestData = GetTestDataDirectory(); mPathToAnalysisTestData = mPathToTestData + "SMSAnalysisTests/"; mReader.GetOutPort("Samples Read").ConnectToIn( mAnalysis.GetInPort("Input Audio")); CLAM::TSize frameSize = 256; mReader.GetOutPort("Samples Read").SetSize( frameSize ); mReader.GetOutPort("Samples Read").SetHop( frameSize ); //mReader.GetOutPort("Samples Read").CenterEvenRegions(); } void setUp() { mAnalysis.Start(); } void tearDown() { mAnalysis.Stop(); } void testPathToFiles() { std::string msg = "Cound't open this file: " + mPathToTestData+"sine.wav"; CPPUNIT_ASSERT_MESSAGE(msg, helperFileExist(mPathToTestData+"sine.wav")); } void testSine_comparingSegment() { CLAM::AudioFile file; file.OpenExisting( mPathToTestData + "sine.wav" ); CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( file ); CLAM::MonoAudioFileReader wholeFileReader; wholeFileReader.GetOutPort("Samples Read").SetSize( file.GetHeader().GetSamples() ); wholeFileReader.GetOutPort("Samples Read").SetHop( file.GetHeader().GetSamples() ); wholeFileReader.Configure(cfg); wholeFileReader.Start(); wholeFileReader.Do(); wholeFileReader.Stop(); CLAM::Segment segment; CLAM::OutPortBase & outAudio = wholeFileReader.GetOutPort("Samples Read" ); segment.SetAudio( CLAM::AudioOutPort::GetLastWrittenAudio( outAudio ) ); CLAM::SMSAnalysisConfig cfgAnalysis; cfgAnalysis.SetSamplingRate( file.GetHeader().GetSampleRate() ); CLAM::SMSAnalysis analysis; analysis.Configure( cfgAnalysis ); analysis.Start(); analysis.Do( segment ); analysis.Stop(); // CLAM::XMLStorage::Dump(segment, "Data", mPathToTestData + "/SMSAnalysisTests/sine_segment.xml" ); CPPUNIT_ASSERT_EQUAL( StringFromFile(mPathToTestData+"/SMSAnalysisTests/sine_segment.xml" ), StringFromData(segment) ); } void testSweep_comparingSegment() { CLAM::AudioFile file; file.OpenExisting( mPathToTestData + "sweep.wav" ); CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( file ); CLAM::MonoAudioFileReader wholeFileReader; wholeFileReader.GetOutPort( "Samples Read" ).SetSize( file.GetHeader().GetSamples() ); wholeFileReader.GetOutPort( "Samples Read" ).SetHop( file.GetHeader().GetSamples() ); wholeFileReader.Configure( cfg ); wholeFileReader.Start(); wholeFileReader.Do(); wholeFileReader.Stop(); CLAM::Segment segment; CLAM::OutPortBase & outAudio = wholeFileReader.GetOutPort("Samples Read" ); segment.SetAudio( CLAM::AudioOutPort::GetLastWrittenAudio( outAudio ) ); CLAM::SMSAnalysisConfig cfgAnalysis; cfgAnalysis.SetSamplingRate( file.GetHeader().GetSampleRate() ); CLAM::SMSAnalysis analysis; analysis.Configure( cfgAnalysis ); analysis.Start(); analysis.Do( segment ); analysis.Stop(); // CLAM::XMLStorage::Dump(segment, "Data", mPathToTestData + "/SMSAnalysisTests/sweep_segment_ports.xml" ); CPPUNIT_ASSERT_EQUAL( StringFromFile(mPathToTestData+"/SMSAnalysisTests/sweep_segment.xml"), StringFromData(segment) ); } void testTrumpet_comparingSegment() { CLAM::AudioFile file; file.OpenExisting( mPathToTestData + "trumpet.wav" ); CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( file ); CLAM::MonoAudioFileReader wholeFileReader; wholeFileReader.GetOutPort( "Samples Read" ).SetSize( file.GetHeader().GetSamples() ); wholeFileReader.GetOutPort( "Samples Read" ).SetHop( file.GetHeader().GetSamples() ); wholeFileReader.Configure( cfg ); wholeFileReader.Start(); wholeFileReader.Do(); wholeFileReader.Stop(); CLAM::Segment segment; CLAM::OutPortBase & outAudio = wholeFileReader.GetOutPort("Samples Read" ); segment.SetAudio( CLAM::AudioOutPort::GetLastWrittenAudio( outAudio ) ); CLAM::SMSAnalysisConfig cfgAnalysis; cfgAnalysis.SetSamplingRate( file.GetHeader().GetSampleRate() ); CLAM::SMSAnalysis analysis; analysis.Configure( cfgAnalysis ); analysis.Start(); analysis.Do( segment ); analysis.Stop(); // CLAM::XMLStorage::Dump(segment, "Data", mPathToTestData + "/SMSAnalysisTests/trumpet_segment_ports.xml" ); CPPUNIT_ASSERT_EQUAL( StringFromFile(mPathToTestData+"/SMSAnalysisTests/trumpet_segment.xml"), StringFromData(segment) ); } void testInnerData_withSound(const std::string& soundName ) { LoadAudioFile( mPathToTestData + soundName + ".wav" ); DoReaderAndAnalysis(); DoReaderAndAnalysis(); /* // For getting the "good" xml files CLAM::XMLStorage::Dump(outputSpectrum, "Data", mPathToTestData + "/SMSAnalysisTests/outputSpectrum_sine.xml" ); CLAM::XMLStorage::Dump(outputSinSpectrum, "Data", mPathToTestData + "/SMSAnalysisTests/outputSinSpectrum_sine.xml" ); CLAM::XMLStorage::Dump(outputSpectralPeaks, "Data",mPathToTestData + "/SMSAnalysisTests/outputSpectralPeaks_sine.xml" ); CLAM::XMLStorage::Dump(outputFundamental, "Data",mPathToTestData + "/SMSAnalysisTests/outputFundamental_sine.xml" ); CLAM::XMLStorage::Dump(outputResSpectrum, "Data",mPathToTestData + "/SMSAnalysisTests/outputResSpectrum_sine.xml" ); */ { CLAM::OutPortBase & outPort = mAnalysis.GetOutPort("Residual Branch Spectrum"); CLAM::Spectrum & out = CLAM::OutPortPublisher::GetLastWrittenData( outPort); CPPUNIT_ASSERT_EQUAL( StringFromFile(mPathToAnalysisTestData+"outputSpectrum_"+soundName+".xml" ), StringFromData(out ) ); } { CLAM::OutPortBase & outPort = mAnalysis.GetOutPort("Sinusoidal Branch Spectrum"); CLAM::Spectrum & out = CLAM::OutPortPublisher::GetLastWrittenData( outPort); CPPUNIT_ASSERT_EQUAL( StringFromFile( mPathToAnalysisTestData+"outputSinSpectrum_"+soundName+".xml" ), StringFromData(out) ); } { CLAM::OutPortBase & outPort = mAnalysis.GetOutPort("Sinusoidal Peaks"); CLAM::SpectralPeakArray & out = CLAM::OutPortPublisher::GetLastWrittenData( outPort); CPPUNIT_ASSERT_EQUAL( StringFromFile( mPathToAnalysisTestData+"outputSpectralPeaks_"+soundName+".xml" ), StringFromData(out) ); } { CLAM::OutPortBase & outPort = mAnalysis.GetOutPort("Fundamental"); CLAM::Fundamental & out = CLAM::OutPortPublisher::GetLastWrittenData( outPort); CPPUNIT_ASSERT_EQUAL( StringFromFile( mPathToAnalysisTestData+"outputFundamental_"+soundName+".xml" ), StringFromData(out) ); } { CLAM::OutPortBase & outPort = mAnalysis.GetOutPort("Residual Spectrum"); CLAM::Spectrum & out = CLAM::OutPortPublisher::GetLastWrittenData( outPort); CPPUNIT_ASSERT_EQUAL( StringFromFile( mPathToAnalysisTestData+"outputResSpectrum_"+soundName+".xml" ), StringFromData(out) ); } mReader.Stop(); } void testSine_innerData() { testInnerData_withSound("sine"); } void testSweep_innerData() { testInnerData_withSound("sweep"); } void testTrumpet_innerData() { testInnerData_withSound("trumpet"); } }; } // namespace CLAMTest clam-1.4.0/test/FunctionalTests/ProcessingTests/similarityHelper.cxx0000644000000000000000000000566710610720021024446 0ustar rootroot#include "similarityHelper.hxx" #include "Assert.hxx" #include "CLAM_Math.hxx" #include "SpectralPeakArray.hxx" namespace CLAMTest { DataSizeMismatch::DataSizeMismatch() throw() : Err( ) { } DataSizeMismatch::DataSizeMismatch( const char* msg ) throw() : Err( msg ) { } DataSizeMismatch::~DataSizeMismatch() throw() { } static double evaluateAverage( const CLAM::DataArray& left ) { double avg = 0.0; for ( int i = 0; i < left.Size(); i++ ) { avg += left[i]; } avg /= double( left.Size() ); return avg; } static double evaluateCovariance( const CLAM::DataArray& left, double leftAverage, const CLAM::DataArray& right, double rightAverage ) { if ( left.Size() != right.Size() ) throw DataSizeMismatch( "Arrays cannot be compared: sizes differ!" ); double cov = 0.0; for ( int i = 0; i < left.Size(); i++ ) { cov+= ( left[i]-leftAverage ) * ( right[i] - rightAverage ); } cov /= double( left.Size() ); return cov; } static double evaluateVariance( const CLAM::DataArray& vector, double average ) { if ( vector.Size() <= 0 ) throw DataSizeMismatch( "Void vector: variance cannot be evaluated" ); double var = 0.0; for ( int i = 0; i < vector.Size(); i++ ) { double tmp = vector[i]-average; tmp *= tmp; var += tmp; } var /= double( vector.Size() ); return var; } double evaluateSimilarity( const CLAM::DataArray& left, const CLAM::DataArray& right ) throw( DataSizeMismatch ) { double leftAverage = evaluateAverage( left ); double rightAverage = evaluateAverage( right ); double covLeftRight = evaluateCovariance( left, leftAverage, right, rightAverage ); double leftVariance = evaluateVariance( left, leftAverage ); double rightVariance = evaluateVariance( right, rightAverage ); double stddevX_times_stddevY = ( sqrt(leftVariance)*sqrt(rightVariance) ); if ( fabs(covLeftRight) < 1e-7 && fabs( stddevX_times_stddevY ) < 1e-7 ) // two vector of nearly zeros return 1.0; return covLeftRight/stddevX_times_stddevY; } void flattenSpectralPeakArray( const CLAM::SpectralPeakArray& in, CLAM::DataArray& out ) { CLAM::TSize flattenedLen = in.GetMagBuffer().Size() + in.GetFreqBuffer().Size() + in.GetPhaseBuffer().Size() + in.GetBinPosBuffer().Size() + in.GetBinWidthBuffer().Size(); out.Resize( flattenedLen ); out.SetSize( flattenedLen ); int i = 0, j = 0; for ( i = 0; i < in.GetMagBuffer().Size(); i++, j++ ) { out[j] = in.GetMagBuffer()[i]; } for ( i = 0; i < in.GetFreqBuffer().Size(); i++, j++ ) { out[j] = in.GetFreqBuffer()[i]; } for ( i = 0; i < in.GetPhaseBuffer().Size(); i++, j++ ) { out[j] = in.GetPhaseBuffer()[i]; } for ( i = 0; i < in.GetBinPosBuffer().Size(); i++, j++ ) { out[j] = in.GetBinPosBuffer()[i]; } for ( i = 0; i < in.GetBinWidthBuffer().Size(); i++, j++ ) { out[j] = in.GetBinWidthBuffer()[i]; } } } clam-1.4.0/test/FunctionalTests/ProcessingTests/TestCepstralTransform.cxx0000644000000000000000000001004010610720021025406 0ustar rootroot#include #include "cppUnitHelper.hxx" // necessary for the custom assert #include "CepstralTransform.hxx" #include "MelSpectrum.hxx" #include "MelCepstrum.hxx" #include "Array.hxx" #include "similarityHelper.hxx" #include "CLAM_Math.hxx" #include #include namespace CLAMTest { class CepstralTransformTest; CPPUNIT_TEST_SUITE_REGISTRATION( CepstralTransformTest ); class CepstralTransformTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( CepstralTransformTest ); CPPUNIT_TEST( test_Configuration ); CPPUNIT_TEST( test_Do_20to13 ); CPPUNIT_TEST( test_Do_20to1 ); CPPUNIT_TEST_SUITE_END(); private: // Back 2 back testing data static CLAM::MelSpectrum mInputMelSpectrum; static CLAM::DataArray m20To13ExpectedValues; static CLAM::DataArray m20To1ExpectedValues; static bool mBack2BackInit; public: /// Common initialization, executed before each test method void setUp() { if ( !mBack2BackInit ) { mBack2BackInit = true; CLAM::TData expected20to13Values[] = { 54.965, 0.265, 2.696, 1.462, 1.551, 1.378, 0.311, 0.610, 0.338, 0.526, -0.350, -0.042, -0.038 }; m20To13ExpectedValues.Resize( 13 ); m20To13ExpectedValues.SetSize( 13 ); std::copy( expected20to13Values, expected20to13Values + 13, m20To13ExpectedValues.GetPtr() ); CLAM::TData expected20to1Values[] = { 54.965 }; m20To1ExpectedValues.Resize( 1 ); m20To1ExpectedValues.SetSize( 1 ); std::copy( expected20to1Values, expected20to1Values + 1, m20To1ExpectedValues.GetPtr() ); mInputMelSpectrum.SetLowCutoff(0); mInputMelSpectrum.SetHighCutoff(22050); CLAM::DataArray& melCoeffs = mInputMelSpectrum.GetCoefficients(); melCoeffs.Resize(20); melCoeffs.SetSize(20); melCoeffs[0] = 84023.047; melCoeffs[1] = 28551.820; melCoeffs[2] = 7897.233; melCoeffs[3] = 3400.617; melCoeffs[4] = 2650.711; melCoeffs[5] = 3125.628; melCoeffs[6] = 2647.331; melCoeffs[7] = 2451.074; melCoeffs[8] = 3440.129; melCoeffs[9] = 5310.415; melCoeffs[10] = 3585.410; melCoeffs[11] = 3259.937; melCoeffs[12] = 3304.838; melCoeffs[13] = 4684.439; melCoeffs[14] = 5098.067; melCoeffs[15] = 6528.634; melCoeffs[16] = 8278.005; melCoeffs[17] = 11910.106; melCoeffs[18] = 11997.375; melCoeffs[19] = 6802.410; } } /// Common clean up, executed after each test method void tearDown() { } private: void test_Configuration() { CLAM::CepstralTransformConfig ctConfig; ctConfig.SetNumMelCoefficients(20); ctConfig.SetNumCepstrumCoefficients(13); CLAM::CepstralTransform proc; CPPUNIT_ASSERT_EQUAL( true, proc.Configure( ctConfig ) ); } void test_Do_20to13() { CLAM::CepstralTransformConfig ctConfig; ctConfig.SetNumMelCoefficients(20); ctConfig.SetNumCepstrumCoefficients(13); CLAM::MelCepstrum melCeps; CLAM::CepstralTransform proc; proc.Configure( ctConfig ); proc.Start(); proc.Do( mInputMelSpectrum, melCeps ); proc.Stop(); double sim = evaluateSimilarity( m20To13ExpectedValues, melCeps.GetCoefficients() ); /* std::cout << sim; std::cout.flush(); */ CPPUNIT_ASSERT( sim >= 0.999 ); } void test_Do_20to1() { CLAM::CepstralTransformConfig ctConfig; ctConfig.SetNumMelCoefficients(20); ctConfig.SetNumCepstrumCoefficients(1); CLAM::MelCepstrum melCeps; CLAM::CepstralTransform proc; proc.Configure( ctConfig ); proc.Start(); proc.Do( mInputMelSpectrum, melCeps ); proc.Stop(); double sim = fabs( m20To1ExpectedValues[0] - melCeps.GetCoefficients()[0] ); sim /= m20To1ExpectedValues[0]; sim = 1.0 - sim; /* std::cout << sim; std::cout.flush(); */ CPPUNIT_ASSERT( sim >= 0.999 ); } }; CLAM::MelSpectrum CepstralTransformTest::mInputMelSpectrum; CLAM::DataArray CepstralTransformTest::m20To13ExpectedValues; CLAM::DataArray CepstralTransformTest::m20To1ExpectedValues; bool CepstralTransformTest::mBack2BackInit = false; } // namespace CLAMTest clam-1.4.0/test/FunctionalTests/ProcessingTests/AudioFileOpsTestsHelper.cxx0000644000000000000000000000354510610720021025617 0ustar rootroot#include "AudioFileOpsTestsHelper.hxx" #include "similarityHelper.hxx" #include "PCMAudioStream.hxx" namespace CLAMTest { double fileSimilarity( const std::string & file, int channel, const CLAM::Audio& rhs ) { CLAM::AudioFileSource source; source.OpenExisting(file); CLAM::AudioCodecs::Stream* stream = source.GetStream(); CLAM::DataArray samplesExtracted; samplesExtracted.Resize( rhs.GetSize() ); samplesExtracted.SetSize( rhs.GetSize() ); stream->PrepareReading(); stream->ReadData( channel, samplesExtracted.GetPtr(), samplesExtracted.Size() ); stream->Dispose(); delete stream; return evaluateSimilarity( samplesExtracted, rhs.GetBuffer() ); } void fileSimilarity( const std::string & file, const CLAM::Audio& left, const CLAM::Audio& right, double& similarityLeft, double& similarityRight ) { CLAM::AudioFileSource source; source.OpenExisting(file); CLAM::AudioCodecs::Stream* stream = source.GetStream(); CLAM::DataArray samplesExtractedLeft; samplesExtractedLeft.Resize( left.GetSize() ); samplesExtractedLeft.SetSize( left.GetSize() ); CLAM::DataArray samplesExtractedRight; samplesExtractedRight.Resize( right.GetSize() ); samplesExtractedRight.SetSize( right.GetSize() ); stream->PrepareReading(); int* channelBuff = new int[2]; channelBuff[0] = 0; channelBuff[1] = 1; CLAM::TData** samplesMatrix = new CLAM::TData*[2]; samplesMatrix[0] = samplesExtractedLeft.GetPtr(); samplesMatrix[1] = samplesExtractedRight.GetPtr(); stream->ReadData( channelBuff, 2, samplesMatrix, left.GetSize() ); stream->Dispose(); similarityLeft = evaluateSimilarity( samplesExtractedLeft, left.GetBuffer() ); similarityRight = evaluateSimilarity( samplesExtractedRight, right.GetBuffer() ); delete channelBuff; delete samplesMatrix; delete stream; } } clam-1.4.0/test/FunctionalTests/ProcessingTests/TestMonoAudioFileWriter.cxx0000644000000000000000000001412211016524554025647 0ustar rootroot#include #include "cppUnitHelper.hxx" #include #include #include #include #include #include "similarityHelper.hxx" #include #include namespace CLAMTest { class MonoAudioFileWriterFunctionalTest; CPPUNIT_TEST_SUITE_REGISTRATION( MonoAudioFileWriterFunctionalTest ); class MonoAudioFileWriterFunctionalTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( MonoAudioFileWriterFunctionalTest ); CPPUNIT_TEST( testConfigure_twoOnTheSameFileFail ); CPPUNIT_TEST( testDo_PCM_WritesTheSameItWasRead ); CPPUNIT_TEST( testDo_OggVorbis_WritesTheSameItWasRead ); CPPUNIT_TEST_SUITE_END(); protected: std::string mPathToTestData; public: void setUp() { mPathToTestData = GetTestDataDirectory(); } void tearDown() { } private: void testConfigure_ReturnsFalse_WithJustFilename() { CLAM::MonoAudioFileWriterConfig cfg; cfg.SetTargetFile( "NewFile.wav" ); CLAM::MonoAudioFileWriter proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( false, configResult ); } void testConfigure_twoOnTheSameFileFail() { CLAM::MonoAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "twosines-stereo.wav" ); CLAM::MonoAudioFileWriter procWriter; CLAM::MonoAudioFileWriter procWriter2; procWriter.Configure( cfgWriter ); CPPUNIT_ASSERT_EQUAL( false, procWriter2.Configure( cfgWriter ) ); } void testDo_PCM_WritesTheSameItWasRead() { CLAM::MonoAudioFileReaderConfig cfgReader; cfgReader.SetSourceFile( mPathToTestData + std::string( "Elvis.wav" ) ); cfgReader.SetSelectedChannel( 0 ); CLAM::MonoAudioFileReader procReader; CPPUNIT_ASSERT_EQUAL( true, procReader.Configure( cfgReader ) ); CLAM::MonoAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "CopyOfElvis.wav.wav" ); cfgWriter.SetSampleRate( procReader.GetHeader().GetSampleRate() ); // TODO: Those parameters have not been moved from the header to configuration // cfgWriter.SetFormat( procReader.GetHeader().GetFormat() ); // cfgWriter.SetEncoding( procReader.GetHeader().GetEncoding() ); // cfgWriter.SetEndianess( procReader.GetHeader().GetEndianess() ); CLAM::MonoAudioFileWriter procWriter; CPPUNIT_ASSERT_EQUAL( true, procWriter.Configure( cfgWriter ) ); CLAM::Audio readSamples; readSamples.SetSize( 256 ); procReader.Start(); procWriter.Start(); int frameCounter = 0; while( procReader.Do(readSamples) ) { frameCounter++; procWriter.Do(readSamples); } procReader.Stop(); procWriter.Stop(); // Once written to disk, now we recover it, and // check it is the same frame by frame CLAM::MonoAudioFileReader procReader2; cfgReader.SetSourceFile( "CopyOfElvis.wav.wav" ); CPPUNIT_ASSERT_EQUAL( true, procReader2.Configure( cfgReader ) ); CLAM::Audio readSamples2; readSamples2.SetSize( 256 ); procReader.Start(); procReader2.Start(); frameCounter = 0; while( procReader.Do(readSamples) && procReader2.Do(readSamples2) ) { double sim = evaluateSimilarity( readSamples.GetBuffer(), readSamples2.GetBuffer() ); CPPUNIT_ASSERT ( sim >= 0.9999 ); } procReader.Stop(); procReader2.Stop(); } void testDo_OggVorbis_WritesTheSameItWasRead() { CLAM::MonoAudioFileReaderConfig cfgReader; cfgReader.SetSourceFile( mPathToTestData + std::string( "Elvis.wav" ) ); cfgReader.SetSelectedChannel( 0 ); CLAM::MonoAudioFileReader procReader; CPPUNIT_ASSERT_EQUAL( true, procReader.Configure( cfgReader ) ); CLAM::MonoAudioFileWriterConfig cfgWriter; cfgWriter.SetTargetFile( "CopyOfElvis.ogg" ); cfgWriter.SetSampleRate( procReader.GetHeader().GetSampleRate() ); CLAM::MonoAudioFileWriter procWriter; CPPUNIT_ASSERT_EQUAL( true, procWriter.Configure( cfgWriter ) ); CLAM::Audio readSamples; readSamples.SetSize( 256 ); procReader.Start(); procWriter.Start(); int framesRead = 0; while( procReader.Do(readSamples) ) { framesRead++; procWriter.Do(readSamples); } procReader.Stop(); procWriter.Stop(); // Once written to disk, now we recover it, and // check it is the same frame by frame CLAM::MonoAudioFileReader procReader2; cfgReader.SetSourceFile( "CopyOfElvis.ogg" ); CPPUNIT_ASSERT_EQUAL( true, procReader2.Configure( cfgReader ) ); CLAM::Audio readSamples2; readSamples2.SetSize( 256 ); procReader.Start(); procReader2.Start(); int framesChecked = 0; double maxSim = -1e20; int maxSimFrame = 0; double minSim = 1e20; int minSimFrame = 0; double averageSim = 0.0; while( procReader.Do(readSamples) && procReader2.Do(readSamples2) ) { double sim = evaluateSimilarity( readSamples.GetBuffer(), readSamples2.GetBuffer() ); framesChecked++; if ( sim > maxSim ) { maxSim = sim; maxSimFrame = framesChecked; } if ( sim < minSim ) { minSim = sim; minSimFrame = framesChecked; } averageSim += sim; // MRJ: Note that due to decoding/encoding approximation errors // correlation is not as higher as in the PCM case. Note we have // put it to 0.5 which is the 'parameter' value for deciding // trade-off between quality and bitrate. CPPUNIT_ASSERT( sim >= 0.5); } averageSim *= (1.0/double(framesChecked)); /* std::cout << std::endl; std::cout << "Maximum similarity: " << maxSim << " at " << maxSimFrame; std::cout << std::endl; std::cout << "Minimum similarity: " << minSim << " at " << minSimFrame; std::cout << std::endl; std::cout << "Average similarity: " << averageSim << std::endl; */ CPPUNIT_ASSERT( fabs( maxSim - 1.0 ) < 1e-2 ); CPPUNIT_ASSERT( fabs( minSim - 0.644362 ) < 1e-2 ); CPPUNIT_ASSERT( fabs( averageSim - 0.99589 ) < 1e-2 ); procReader.Stop(); procReader2.Stop(); CPPUNIT_ASSERT_EQUAL( framesRead, framesChecked ); } }; } clam-1.4.0/test/FunctionalTests/ProcessingTests/AudioFileOpsTestsHelper.hxx0000644000000000000000000000073010610720021025615 0ustar rootroot#ifndef __AUDIOFILEOPSTESTSHELPER__ #define __AUDIOFILEOPSTESTSHELPER__ #include "Audio.hxx" #include "AudioFile.hxx" namespace CLAMTest { double fileSimilarity( const std::string & filename, int channel, const CLAM::Audio& rhs ); void fileSimilarity( const std::string & filename, const CLAM::Audio& left, const CLAM::Audio& right, double& similarityLeft, double& similarityRight ); } #endif // AudioFileOpsTestsHelper.hxx clam-1.4.0/test/FunctionalTests/ProcessingTests/TestControlTraces.cxx0000644000000000000000000001332210613653074024545 0ustar rootroot#include #include "cppUnitHelper.hxx" #include #include "similarityHelper.hxx" #include #include namespace CLAMTest { class ControlTraceReaderFunctionalTest; CPPUNIT_TEST_SUITE_REGISTRATION( ControlTraceReaderFunctionalTest ); class ControlTraceReaderFunctionalTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ControlTraceReaderFunctionalTest ); // Configuration values checking tests CPPUNIT_TEST( testConfigure_ReturnsTrueWithJustFilename ); CPPUNIT_TEST( testConfigure_ReturnsFalseWithoutTraceFileInConfig ); CPPUNIT_TEST( testConfigure_ReturnsTrueWhenFileExists ); CPPUNIT_TEST( testConfigure_ReturnsFalseWhenFileDoesNotExist ); CPPUNIT_TEST( testConfigure_ReturnsTrueWhenTraceEventsExist ); CPPUNIT_TEST( testConfigure_ReturnsFalseWhenTraceFileIsEmpty ); CPPUNIT_TEST_SUITE_END(); protected: // Attributes std::string mInputFileName; std::string mEmptyFileName; protected: // Auxiliary methods public: // TestFixture interface void setUp() { std::string filesPrefix = GetTestDataDirectory() + "controlTraces/ControlTraceReader"; mInputFileName = filesPrefix + "Input.clamtrace"; mEmptyFileName = filesPrefix + "Empty.clamtrace"; } void tearDown() { } private: // tests cases void testConfigure_ReturnsTrueWithJustFilename() { CLAM::ControlTraceReaderConfig cfg; CLAM::ControlTraceInFilename file(mInputFileName); cfg.SetTraceFile( file ); CLAM::ControlTraceReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( true, configResult ); } void testConfigure_ReturnsFalseWithoutTraceFileInConfig() { CLAM::ControlTraceReaderConfig cfg; cfg.RemoveTraceFile(); cfg.UpdateData(); CLAM::ControlTraceReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( false, configResult ); } void testConfigure_ReturnsTrueWhenFileExists() { CLAM::ControlTraceReaderConfig cfg; CLAM::ControlTraceInFilename file(mInputFileName); cfg.SetTraceFile( file ); CLAM::ControlTraceReader proc; bool configResult = proc.Configure( cfg ); if (!configResult) std::cout << proc.GetConfigErrorMessage() << std::endl; CPPUNIT_ASSERT_EQUAL( true, configResult ); } void testConfigure_ReturnsFalseWhenFileDoesNotExist() { CLAM::ControlTraceReaderConfig cfg; CLAM::ControlTraceInFilename file( GetTestDataDirectory() + std::string( "/missing-file.clamtrace" ) ); cfg.SetTraceFile( file ); CLAM::ControlTraceReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( false, configResult ); } void testConfigure_ReturnsTrueWhenTraceEventsExist() { CLAM::ControlTraceReaderConfig cfg; CLAM::ControlTraceInFilename file(mInputFileName); cfg.SetTraceFile( file ); CLAM::ControlTraceReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( true, configResult ); } void testConfigure_ReturnsFalseWhenTraceFileIsEmpty() { CLAM::ControlTraceReaderConfig cfg; CLAM::ControlTraceInFilename file(mEmptyFileName); cfg.SetTraceFile( file ); CLAM::ControlTraceReader proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( false, configResult ); } }; class ControlTraceWriterFunctionalTest; CPPUNIT_TEST_SUITE_REGISTRATION( ControlTraceWriterFunctionalTest ); class ControlTraceWriterFunctionalTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ControlTraceWriterFunctionalTest ); // Configuration values checking tests CPPUNIT_TEST( testConfigure_ReturnsTrueWithJustFilename ); CPPUNIT_TEST( testConfigure_ReturnsFalseWithoutTraceFileInConfig ); CPPUNIT_TEST( testConfigure_ReturnsTrueWhenFileExists ); CPPUNIT_TEST( testConfigure_ReturnsFalseWithoutInputsInConfig ); CPPUNIT_TEST( testConfigure_ReturnsFalseWhenConfiguredWithNoInputs ); CPPUNIT_TEST_SUITE_END(); protected: // Attributes std::string mOutputFileName; protected: // Auxiliary methods public: // TestFixture interface void setUp() { std::string filesPrefix = GetTestDataDirectory() + "ControlTraceWriter"; mOutputFileName = filesPrefix + "Output.clamtrace"; } void tearDown() { } private: // tests cases void testConfigure_ReturnsTrueWithJustFilename() { CLAM::ControlTraceWriterConfig cfg; CLAM::ControlTraceOutFilename file(mOutputFileName); cfg.SetTraceFile( file ); CLAM::ControlTraceWriter proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( true, configResult ); } void testConfigure_ReturnsFalseWithoutTraceFileInConfig() { CLAM::ControlTraceWriterConfig cfg; cfg.RemoveTraceFile(); cfg.UpdateData(); CLAM::ControlTraceWriter proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( false, configResult ); } void testConfigure_ReturnsTrueWhenFileExists() { CLAM::ControlTraceWriterConfig cfg; CLAM::ControlTraceOutFilename file(mOutputFileName); cfg.SetTraceFile( file ); CLAM::ControlTraceWriter proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( true, configResult ); } void testConfigure_ReturnsFalseWithoutInputsInConfig() { CLAM::ControlTraceWriterConfig cfg; cfg.RemoveNumberOfInputs(); cfg.UpdateData(); CLAM::ControlTraceOutFilename file(mOutputFileName); cfg.SetTraceFile( file ); CLAM::ControlTraceWriter proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( false, configResult ); } void testConfigure_ReturnsFalseWhenConfiguredWithNoInputs() { CLAM::ControlTraceWriterConfig cfg; CLAM::ControlTraceOutFilename file(mOutputFileName); cfg.SetTraceFile( file ); cfg.SetNumberOfInputs( 0 ); CLAM::ControlTraceWriter proc; bool configResult = proc.Configure( cfg ); CPPUNIT_ASSERT_EQUAL( false, configResult ); } }; } clam-1.4.0/test/FunctionalTests/Applications/0000755000000000000000000000000011344231441017655 5ustar rootrootclam-1.4.0/test/FunctionalTests/Applications/README.txt0000644000000000000000000000021507751715520021365 0ustar rootrootFunctional tests of applications (use of façade classes is likely) note that functional processing tests goes to ../ProcessingTests directoryclam-1.4.0/test/FunctionalTests/Applications/MIRTests/0000755000000000000000000000000011344231441021327 5ustar rootrootclam-1.4.0/test/FunctionalTests/Applications/MIRTests/TickExtractorTest.cxx0000644000000000000000000005331410610720021025477 0ustar rootroot#include #include "cppUnitHelper.hxx" // necessary for the custom assert #include "RhythmDescriptionHelpers.hxx" #include "TickExtractor.hxx" #include "TickExtractorConfig.hxx" #include "XMLStorage.hxx" namespace CLAMTest { class TickExtractorTest; CPPUNIT_TEST_SUITE_REGISTRATION( TickExtractorTest ); class TickExtractorTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( TickExtractorTest ); CPPUNIT_TEST( test_02_alles_Ticks ); CPPUNIT_TEST( test_12_cubic_Ticks ); CPPUNIT_TEST( test_ALoCubano_Ticks ); CPPUNIT_TEST( test_AmourEnPoudre_Ticks ); CPPUNIT_TEST( test_Amsterdam_Ticks ); CPPUNIT_TEST( test_blue_monday_Ticks ); CPPUNIT_TEST( test_clicseq_Ticks ); CPPUNIT_TEST( test_drums_electronic_guit_Ticks ); CPPUNIT_TEST( test_elecpiano_drums_Ticks ); CPPUNIT_TEST( test_test1_Ticks ); CPPUNIT_TEST( test_test2_Ticks ); CPPUNIT_TEST( test_test_Ticks ); CPPUNIT_TEST_SUITE_END(); protected: std::string mPathToTests; std::string mOnsetDetectionAlgorithm; CLAM::Pulse extractedBeats; public: void setUp() { mPathToTests = "../../../../../CLAM-TestData/RhythmDescription"; mOnsetDetectionAlgorithm = "MTG"; } void tearDown() { } private: void test_02_alles_Ticks() { RhythmDescriptionTests::RhythmEventsB2B inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Tick/02_alles_Ticks.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Tick/02_alles_Ticks.xml", inst.IsValid() == true); CLAM::Pulse extractedEvents; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/" + inst.GetRelativePath(), cfg, extractedEvents, extractedBeats ); RhythmDescriptionTests::RhythmEventsB2B res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "RhythmEventsB2B", "02_alles_Ticks.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents().GetIndexes(), extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "test_Ticks_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().GetIndexes().Size(), extractedEvents.GetIndexes().Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check test_Ticks_diff.xml!", diff.GetMaxTimePositionDeviation() <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check test_Ticks_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); CPPUNIT_ASSERT_EQUAL( int(inst.GetEvents().GetRate()), int(extractedEvents.GetRate()) ); } void test_12_cubic_Ticks() { RhythmDescriptionTests::RhythmEventsB2B inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Tick/12_cubic_Ticks.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Tick/12_cubic_Ticks.xml", inst.IsValid() == true ); CLAM::Pulse extractedEvents; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod(mOnsetDetectionAlgorithm) ); CLAM::ExtractTicksSequence( mPathToTests + "/" + inst.GetRelativePath(), cfg, extractedEvents, extractedBeats ); RhythmDescriptionTests::RhythmEventsB2B res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "RhythmEventsB2B", "12_cubic_Ticks.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents().GetIndexes(), extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "12_cubic_Ticks_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().GetIndexes().Size(), extractedEvents.GetIndexes().Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check 12_cubic_Ticks_diff.xml!", diff.GetMaxTimePositionDeviation() <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check 12_cubic_Ticks_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); CPPUNIT_ASSERT_EQUAL( int(inst.GetEvents().GetRate()), int(extractedEvents.GetRate()) ); } void test_blue_monday_Ticks() { RhythmDescriptionTests::RhythmEventsB2B inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Tick/blue_monday_Ticks.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Tick/blue_monday_Ticks.xml", inst.IsValid() == true); CLAM::Pulse extractedEvents; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod(mOnsetDetectionAlgorithm) ); CLAM::ExtractTicksSequence( mPathToTests + "/" + inst.GetRelativePath(), cfg, extractedEvents, extractedBeats ); RhythmDescriptionTests::RhythmEventsB2B res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "RhythmEventsB2B", "blue_monday_Ticks.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents().GetIndexes(), extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "blue_monday_Ticks_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().GetIndexes().Size(), extractedEvents.GetIndexes().Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check blue_monday_Ticks_diff.xml!", diff.GetMaxTimePositionDeviation() <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check blue_monday_Ticks_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); CPPUNIT_ASSERT_EQUAL( int(inst.GetEvents().GetRate()), int(extractedEvents.GetRate()) ); } void test_ALoCubano_Ticks() { RhythmDescriptionTests::RhythmEventsB2B inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Tick/ALoCubano_Ticks.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Tick/ALoCubano_Ticks.xml", inst.IsValid() == true); CLAM::Pulse extractedEvents; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/" + inst.GetRelativePath(), cfg, extractedEvents, extractedBeats ); RhythmDescriptionTests::RhythmEventsB2B res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "RhythmEventsB2B", "ALoCubano_Ticks.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents().GetIndexes(), extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "ALoCubano_Ticks_diff.xml" ); RhythmDescriptionTests::TickSequence ideal; CLAM::XMLStorage::Restore( ideal, mPathToTests + "/Tick/ALoCubano_IdealTickSequence.xml" ); RhythmDescriptionTests::EventListDifference diffWithIdeal; diffWithIdeal.SetFileTested( inst.GetRelativePath() ); diffWithIdeal.CompareWithIdeal( ideal, extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diffWithIdeal, "EventListDifference", "ALoCubano_IdealTicks_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().GetIndexes().Size(), extractedEvents.GetIndexes().Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check ALoCubano_Ticks_diff.xml!", diff.GetMaxTimePositionDeviation() <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check ALoCubano_Ticks_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); CPPUNIT_ASSERT_EQUAL( int(inst.GetEvents().GetRate()), int(extractedEvents.GetRate()) ); } void test_AmourEnPoudre_Ticks() { RhythmDescriptionTests::RhythmEventsB2B inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Tick/AmourEnPoudre_Ticks.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Tick/AmourEnPoudre_Ticks.xml", inst.IsValid() == true); CLAM::Pulse extractedEvents; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/" + inst.GetRelativePath(), cfg, extractedEvents, extractedBeats ); RhythmDescriptionTests::RhythmEventsB2B res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "RhythmEventsB2B", "AmourEnPoudre_Ticks.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents().GetIndexes(), extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "AmourEnPoudre_Ticks_diff.xml" ); RhythmDescriptionTests::TickSequence ideal; CLAM::XMLStorage::Restore( ideal, mPathToTests + "/Tick/AmourEnPoudre_IdealTickSequence.xml" ); RhythmDescriptionTests::EventListDifference diffWithIdeal; diffWithIdeal.SetFileTested( inst.GetRelativePath() ); diffWithIdeal.CompareWithIdeal( ideal, extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diffWithIdeal, "EventListDifference", "AmourEnPoudre_IdealTicks_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().GetIndexes().Size(), extractedEvents.GetIndexes().Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check AmourEnPoudre_Ticks_diff.xml!", diff.GetMaxTimePositionDeviation() <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check AmourEnPoudre_Ticks_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); CPPUNIT_ASSERT_EQUAL( int(inst.GetEvents().GetRate()), int(extractedEvents.GetRate()) ); } void test_Amsterdam_Ticks() { RhythmDescriptionTests::RhythmEventsB2B inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Tick/Amsterdam_Ticks.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Tick/Amsterdam_Ticks.xml", inst.IsValid() == true); CLAM::Pulse extractedEvents; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/" + inst.GetRelativePath(), cfg, extractedEvents, extractedBeats ); RhythmDescriptionTests::RhythmEventsB2B res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "RhythmEventsB2B", "Amsterdam_Ticks.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents().GetIndexes(), extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "Amsterdam_Ticks_diff.xml" ); RhythmDescriptionTests::TickSequence ideal; CLAM::XMLStorage::Restore( ideal, mPathToTests + "/Tick/Amsterdam_IdealTickSequence.xml" ); RhythmDescriptionTests::EventListDifference diffWithIdeal; diffWithIdeal.SetFileTested( inst.GetRelativePath() ); diffWithIdeal.CompareWithIdeal( ideal, extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diffWithIdeal, "EventListDifference", "Amsterdam_IdealTicks_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().GetIndexes().Size(), extractedEvents.GetIndexes().Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check Amsterdam_Ticks_diff.xml!", diff.GetMaxTimePositionDeviation() <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check Amsterdam_Ticks_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); CPPUNIT_ASSERT_EQUAL( int(inst.GetEvents().GetRate()), int(extractedEvents.GetRate()) ); } void test_clicseq_Ticks() { RhythmDescriptionTests::RhythmEventsB2B inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Tick/clicseq_Ticks.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Tick/clicseq_Ticks.xml", inst.IsValid() == true); CLAM::Pulse extractedEvents; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/" + inst.GetRelativePath(), cfg, extractedEvents, extractedBeats ); RhythmDescriptionTests::RhythmEventsB2B res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "RhythmEventsB2B", "clicseq_Ticks.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents().GetIndexes(), extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "clicseq_Ticks_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().GetIndexes().Size(), extractedEvents.GetIndexes().Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check clicseq_Ticks_diff.xml!", diff.GetMaxTimePositionDeviation() <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check clicseq_Ticks_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); CPPUNIT_ASSERT_EQUAL( int(inst.GetEvents().GetRate()), int(extractedEvents.GetRate()) ); } void test_drums_electronic_guit_Ticks() { RhythmDescriptionTests::RhythmEventsB2B inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Tick/drums-electronic-guit_Ticks.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Tick/drums-electronic-guit_Ticks.xml", inst.IsValid() == true); CLAM::Pulse extractedEvents; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/" + inst.GetRelativePath(), cfg, extractedEvents, extractedBeats ); RhythmDescriptionTests::RhythmEventsB2B res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "RhythmEventsB2B", "drums-electronic-guit_Ticks.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents().GetIndexes(), extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "drums-electronic-guit_Ticks_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().GetIndexes().Size(), extractedEvents.GetIndexes().Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check drums-electronic-guit_Ticks_diff.xml!", diff.GetMaxTimePositionDeviation() <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check drums-electronic-guit_Ticks_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); CPPUNIT_ASSERT_EQUAL( int(inst.GetEvents().GetRate()), int(extractedEvents.GetRate()) ); } void test_elecpiano_drums_Ticks() { RhythmDescriptionTests::RhythmEventsB2B inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Tick/elecpiano-drums_Ticks.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Tick/elecpiano-drums_Ticks.xml", inst.IsValid() == true); CLAM::Pulse extractedEvents; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/" + inst.GetRelativePath(), cfg, extractedEvents, extractedBeats ); RhythmDescriptionTests::RhythmEventsB2B res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "RhythmEventsB2B", "elecpiano-drums_Ticks.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents().GetIndexes(), extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "elecpiano-drums_Ticks_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().GetIndexes().Size(), extractedEvents.GetIndexes().Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check elecpiano-drums_Ticks_diff.xml!", diff.GetMaxTimePositionDeviation() <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check elecpiano-drums_Ticks_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); CPPUNIT_ASSERT_EQUAL( int(inst.GetEvents().GetRate()), int(extractedEvents.GetRate()) ); } void test_test1_Ticks() { RhythmDescriptionTests::RhythmEventsB2B inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Tick/test1_Ticks.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Tick/test1_Ticks.xml", inst.IsValid() == true); CLAM::Pulse extractedEvents; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/" + inst.GetRelativePath(), cfg, extractedEvents, extractedBeats ); RhythmDescriptionTests::RhythmEventsB2B res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "RhythmEventsB2B", "test1_Ticks.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents().GetIndexes(), extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "test1_Ticks_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().GetIndexes().Size(), extractedEvents.GetIndexes().Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check test1_Ticks_diff.xml!", diff.GetMaxTimePositionDeviation() <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check test1_Ticks_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); CPPUNIT_ASSERT_EQUAL( int(inst.GetEvents().GetRate()), int(extractedEvents.GetRate()) ); } void test_test2_Ticks() { RhythmDescriptionTests::RhythmEventsB2B inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Tick/test2_Ticks.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Tick/test2_Ticks.xml", inst.IsValid() == true); CLAM::Pulse extractedEvents; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/" + inst.GetRelativePath(), cfg, extractedEvents, extractedBeats ); RhythmDescriptionTests::RhythmEventsB2B res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "RhythmEventsB2B", "test2_Ticks.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents().GetIndexes(), extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "test2_Ticks_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().GetIndexes().Size(), extractedEvents.GetIndexes().Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check test2_Ticks_diff.xml!", diff.GetMaxTimePositionDeviation() <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check test2_Ticks_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); CPPUNIT_ASSERT_EQUAL( int(inst.GetEvents().GetRate()), int(extractedEvents.GetRate()) ); } void test_test_Ticks() { RhythmDescriptionTests::RhythmEventsB2B inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Tick/test_Ticks.xml" ); CPPUNIT_ASSERT_MESSAGE( "Error loading back to back test data: problem with RhythmDescription/Tick/test_Ticks.xml", inst.IsValid() == true); CLAM::Pulse extractedEvents; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/" + inst.GetRelativePath(), cfg, extractedEvents, extractedBeats ); RhythmDescriptionTests::RhythmEventsB2B res; res.AddAll(); res.UpdateData(); res.SetRelativePath( inst.GetRelativePath() ); res.SetEvents( extractedEvents ); CLAM::XMLStorage::Dump( res, "RhythmEventsB2B", "test_Ticks.xml" ); RhythmDescriptionTests::EventListDifference diff; diff.SetFileTested( inst.GetRelativePath() ); diff.Compare( inst.GetEvents().GetIndexes(), extractedEvents.GetIndexes() ); CLAM::XMLStorage::Dump( diff, "EventListDifference", "test_Ticks_diff.xml" ); CPPUNIT_ASSERT_EQUAL( inst.GetEvents().GetIndexes().Size(), extractedEvents.GetIndexes().Size() ); CPPUNIT_ASSERT_MESSAGE("Maximum time position difference above 30 ms! Check test_Ticks_diff.xml!", diff.GetMaxTimePositionDeviation() <= 0.03 ); CPPUNIT_ASSERT_MESSAGE("Maximum weight difference above 0.5! Check test_Ticks_diff.xml!", diff.GetMaxWeightDeviation() <= 0.5 ); CPPUNIT_ASSERT_EQUAL( int(inst.GetEvents().GetRate()), int(extractedEvents.GetRate()) ); } }; } clam-1.4.0/test/FunctionalTests/Applications/MIRTests/RhythmDescriptionHelpers.hxx0000644000000000000000000000513710610720021027060 0ustar rootroot#ifndef __RHYTHMDESCRIPTIONHELPERS__ #define __RHYTHMDESCRIPTIONHELPERS__ #include "DynamicType.hxx" #include "Text.hxx" #include "Array.hxx" #include "DataTypes.hxx" #include "Pulse.hxx" #include "Audio.hxx" namespace CLAMTest { namespace RhythmDescriptionTests { class RhythmEventsB2B : public CLAM::DynamicType { DYNAMIC_TYPE( RhythmEventsB2B, 2 ); DYN_ATTRIBUTE( 0, public, CLAM::Text, RelativePath ); DYN_ATTRIBUTE( 1, public, CLAM::Pulse, Events ); protected: void DefaultInit(); public: bool IsValid() const; }; class TransientEventList : public CLAM::DynamicType { DYNAMIC_TYPE( TransientEventList, 2 ); DYN_ATTRIBUTE( 0, public, CLAM::Text, RelativePath ); DYN_ATTRIBUTE( 1, public, CLAM::Array< CLAM::TimeIndex >, Events ); protected: void DefaultInit(); public: bool IsValid() const; }; class IOIHistogramB2B : public CLAM::DynamicType { DYNAMIC_TYPE( IOIHistogramB2B, 2 ); DYN_ATTRIBUTE( 0, public, CLAM::Text, RelativePath ); DYN_ATTRIBUTE( 1, public, CLAM::Audio, IOIHistogram ); protected: void DefaultInit(); public: bool IsValid() const; }; class TickSequence : public CLAM::DynamicType { DYNAMIC_TYPE( TickSequence, 2 ); DYN_ATTRIBUTE( 0, public, CLAM::Text, RelativePath ); DYN_ATTRIBUTE( 1, public, CLAM::DataArray, TickSequence ); protected: void DefaultInit(); }; class EventListDifference : public CLAM::DynamicType { DYNAMIC_TYPE( EventListDifference, 9 ); DYN_ATTRIBUTE( 0, public, CLAM::Text, FileTested ); DYN_ATTRIBUTE( 1, public, bool, LengthMatched ); DYN_ATTRIBUTE( 2, public, CLAM::Array< CLAM::TimeIndex >, Difference ); DYN_ATTRIBUTE( 3, public, CLAM::TData, AveragePositionDeviation ); DYN_ATTRIBUTE( 4, public, CLAM::TData, AverageWeightDeviation ); DYN_ATTRIBUTE( 5, public, CLAM::TData, MinTimePositionDeviation ); DYN_ATTRIBUTE( 6, public, CLAM::TData, MaxTimePositionDeviation ); DYN_ATTRIBUTE( 7, public, CLAM::TData, MinWeightDeviation ); DYN_ATTRIBUTE( 8, public, CLAM::TData, MaxWeightDeviation ); protected: void DefaultInit(); public: void Compare( const CLAM::Array< CLAM::TimeIndex >& truth, const CLAM::Array< CLAM::TimeIndex >& yield ); void CompareWithIdeal( const TickSequence& ideal, const CLAM::Array< CLAM::TimeIndex >& yield ); }; } } #endif // RhythmDescriptionHelpers.hxx clam-1.4.0/test/FunctionalTests/Applications/MIRTests/MeterExtractorTest.cxx0000644000000000000000000003576610610720021025674 0ustar rootroot#include #include "cppUnitHelper.hxx" // necessary for the custom assert #include "RhythmDescriptionHelpers.hxx" #include "TickExtractor.hxx" #include "TickExtractorConfig.hxx" #include "Meter.hxx" #include "RD_MeterEstimator.hxx" #include "AudioFile.hxx" #include "MonoAudioFileReader.hxx" #include "XMLStorage.hxx" namespace CLAMTest { class MeterEstimatorTest; CPPUNIT_TEST_SUITE_REGISTRATION( MeterEstimatorTest ); class MeterEstimatorTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( MeterEstimatorTest ); CPPUNIT_TEST( test_02_alles_Ticks ); CPPUNIT_TEST( test_12_cubic_Ticks ); CPPUNIT_TEST( test_ALoCubano_Ticks ); CPPUNIT_TEST( test_AmourEnPoudre_Ticks ); CPPUNIT_TEST( test_Amsterdam_Ticks ); CPPUNIT_TEST( test_blue_monday_Ticks ); CPPUNIT_TEST( test_clicseq_Ticks ); CPPUNIT_TEST( test_drums_electronic_guit_Ticks ); CPPUNIT_TEST( test_elecpiano_drums_Ticks ); CPPUNIT_TEST( test_test1_Ticks ); CPPUNIT_TEST( test_test2_Ticks ); CPPUNIT_TEST( test_test_Ticks ); CPPUNIT_TEST_SUITE_END(); protected: std::string mPathToTests; std::string mOnsetDetectionAlgorithm; CLAM::RhythmDescription::MeterEstimatorConfig mMeterEstCfg; void LoadAudio( const std::string& audioFileName, CLAM::Audio& audio ) { CLAM::AudioFile file; file.SetLocation( audioFileName ); if ( !file.IsReadable() ) { throw CLAM::Err( "Could not open file!" ); } CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile( file ); CLAM::MonoAudioFileReader reader; reader.Configure( cfg ); CLAM::TSize fileSize = file.GetHeader().GetSamples(); audio.SetSize(fileSize); audio.SetSampleRate(file.GetHeader().GetSampleRate()); //Read Audio File reader.Start(); reader.Do(audio); reader.Stop(); } public: void setUp() { mPathToTests = "../../../../../CLAM-TestData/RhythmDescription"; mOnsetDetectionAlgorithm = "MTG"; mMeterEstCfg.SetTempoLimInf( 50 ); mMeterEstCfg.SetTempoLimSup( 200 ); mMeterEstCfg.SetAutomaticIntegTime( true ); mMeterEstCfg.SetACFIntegrationTime( 40 ); } void tearDown() { } private: void test_02_alles_Ticks() { CLAM::RhythmDescription::Meter inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Meter/02_alles_Meter.xml" ); CLAM::Pulse extractedEvents; CLAM::Pulse extractedBeats; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/Data/02_alles.wav", cfg, extractedEvents, extractedBeats ); CLAM::Audio signal; LoadAudio( mPathToTests + "/Data/02_alles.wav", signal ); CLAM::RhythmDescription::Meter result; CLAM::RhythmDescription::MeterEstimator meterEstimator; meterEstimator.Configure( mMeterEstCfg ); meterEstimator.Start(); meterEstimator.Log() << "Processing 02_alles.wav" << std::endl; meterEstimator.Do( signal, extractedBeats, result ); meterEstimator.Stop(); CLAM::XMLStorage::Dump( result, "Meter", "02_alles_Meter.xml"); CPPUNIT_ASSERT_EQUAL( inst.GetNumerator(), result.GetNumerator() ); CPPUNIT_ASSERT_EQUAL( inst.GetDenominator(), result.GetDenominator() ); } void test_12_cubic_Ticks() { CLAM::RhythmDescription::Meter inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Meter/12_cubic_Meter.xml" ); CLAM::Pulse extractedEvents; CLAM::Pulse extractedBeats; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod(mOnsetDetectionAlgorithm) ); CLAM::ExtractTicksSequence( mPathToTests + "/Data/12_cubic.wav", cfg, extractedEvents, extractedBeats ); CLAM::Audio signal; LoadAudio( mPathToTests + "/Data/12_cubic.wav", signal ); CLAM::RhythmDescription::Meter result; CLAM::RhythmDescription::MeterEstimator meterEstimator; meterEstimator.Configure( mMeterEstCfg ); meterEstimator.Start(); meterEstimator.Log() << "Processing 12_cubic.wav" << std::endl; meterEstimator.Do( signal, extractedBeats, result ); meterEstimator.Stop(); CLAM::XMLStorage::Dump( result, "Meter", "12_cubic_Meter.xml"); CPPUNIT_ASSERT_EQUAL( inst.GetNumerator(), result.GetNumerator() ); CPPUNIT_ASSERT_EQUAL( inst.GetDenominator(), result.GetDenominator() ); } void test_blue_monday_Ticks() { CLAM::RhythmDescription::Meter inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Meter/blue_monday_Meter.xml" ); CLAM::Pulse extractedEvents; CLAM::Pulse extractedBeats; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod(mOnsetDetectionAlgorithm) ); CLAM::ExtractTicksSequence( mPathToTests + "/Data/blue_monday.wav", cfg, extractedEvents, extractedBeats ); CLAM::Audio signal; LoadAudio( mPathToTests + "/Data/blue_monday.wav", signal ); CLAM::RhythmDescription::Meter result; CLAM::RhythmDescription::MeterEstimator meterEstimator; meterEstimator.Configure( mMeterEstCfg ); meterEstimator.Start(); meterEstimator.Log() << "Processing blue_monday.wav" << std::endl; meterEstimator.Do( signal, extractedBeats, result ); meterEstimator.Stop(); CLAM::XMLStorage::Dump( result, "Meter", "blue_monday_Meter.xml"); CPPUNIT_ASSERT_EQUAL( inst.GetNumerator(), result.GetNumerator() ); CPPUNIT_ASSERT_EQUAL( inst.GetDenominator(), result.GetDenominator() ); } void test_ALoCubano_Ticks() { CLAM::RhythmDescription::Meter inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Meter/ALoCubano_Meter.xml" ); CLAM::Pulse extractedEvents; CLAM::Pulse extractedBeats; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/Data/ALoCubano.wav", cfg, extractedEvents, extractedBeats ); CLAM::Audio signal; LoadAudio( mPathToTests + "/Data/ALoCubano.wav", signal ); CLAM::RhythmDescription::Meter result; CLAM::RhythmDescription::MeterEstimator meterEstimator; meterEstimator.Configure( mMeterEstCfg ); meterEstimator.Start(); meterEstimator.Log() << "Processing ALoCubano.wav" << std::endl; meterEstimator.Do( signal, extractedBeats, result ); meterEstimator.Stop(); CLAM::XMLStorage::Dump( result, "Meter", "ALoCubano_Meter.xml"); CPPUNIT_ASSERT_EQUAL( inst.GetNumerator(), result.GetNumerator() ); CPPUNIT_ASSERT_EQUAL( inst.GetDenominator(), result.GetDenominator() ); } void test_AmourEnPoudre_Ticks() { CLAM::RhythmDescription::Meter inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Meter/AmourEnPoudre_Meter.xml" ); CLAM::Pulse extractedEvents; CLAM::Pulse extractedBeats; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/Data/AmourEnPoudre.wav", cfg, extractedEvents, extractedBeats ); CLAM::Audio signal; LoadAudio( mPathToTests + "/Data/AmourEnPoudre.wav", signal ); CLAM::RhythmDescription::Meter result; CLAM::RhythmDescription::MeterEstimator meterEstimator; meterEstimator.Configure( mMeterEstCfg ); meterEstimator.Start(); meterEstimator.Log() << "Processing AmourEnPoudre.wav" << std::endl; meterEstimator.Do( signal, extractedBeats, result ); meterEstimator.Stop(); CLAM::XMLStorage::Dump( result, "Meter", "AmourEnPoudre_Meter.xml"); CPPUNIT_ASSERT_EQUAL( inst.GetNumerator(), result.GetNumerator() ); CPPUNIT_ASSERT_EQUAL( inst.GetDenominator(), result.GetDenominator() ); } void test_Amsterdam_Ticks() { CLAM::RhythmDescription::Meter inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Meter/Amsterdam_Meter.xml" ); CLAM::Pulse extractedEvents; CLAM::Pulse extractedBeats; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/Data/Amsterdam.wav", cfg, extractedEvents, extractedBeats ); CLAM::Audio signal; LoadAudio( mPathToTests + "/Data/Amsterdam.wav", signal ); CLAM::RhythmDescription::Meter result; CLAM::RhythmDescription::MeterEstimator meterEstimator; meterEstimator.Configure( mMeterEstCfg ); meterEstimator.Start(); meterEstimator.Log() << "Processing Amsterdam.wav" << std::endl; meterEstimator.Do( signal, extractedBeats, result ); meterEstimator.Stop(); CLAM::XMLStorage::Dump( result, "Meter", "Amsterdam_Meter.xml"); CPPUNIT_ASSERT_EQUAL( inst.GetNumerator(), result.GetNumerator() ); CPPUNIT_ASSERT_EQUAL( inst.GetDenominator(), result.GetDenominator() ); } void test_clicseq_Ticks() { CLAM::RhythmDescription::Meter inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Meter/clicseq_Meter.xml" ); CLAM::Pulse extractedEvents; CLAM::Pulse extractedBeats; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/Data/clicseq.wav", cfg, extractedEvents, extractedBeats ); CLAM::Audio signal; LoadAudio( mPathToTests + "/Data/clicseq.wav", signal ); CLAM::RhythmDescription::Meter result; CLAM::RhythmDescription::MeterEstimator meterEstimator; meterEstimator.Configure( mMeterEstCfg ); meterEstimator.Start(); meterEstimator.Log() << "Processing clicseq.wav" << std::endl; meterEstimator.Do( signal, extractedBeats, result ); meterEstimator.Stop(); CLAM::XMLStorage::Dump( result, "Meter", "clicseq_Meter.xml"); CPPUNIT_ASSERT_EQUAL( inst.GetNumerator(), result.GetNumerator() ); CPPUNIT_ASSERT_EQUAL( inst.GetDenominator(), result.GetDenominator() ); } void test_drums_electronic_guit_Ticks() { CLAM::RhythmDescription::Meter inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Meter/drums-electronic-guit_Meter.xml" ); CLAM::Pulse extractedEvents; CLAM::Pulse extractedBeats; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/Data/drums-electronic-guit.wav", cfg, extractedEvents, extractedBeats ); CLAM::Audio signal; LoadAudio( mPathToTests + "/Data/drums-electronic-guit.wav", signal ); CLAM::RhythmDescription::Meter result; CLAM::RhythmDescription::MeterEstimator meterEstimator; meterEstimator.Configure( mMeterEstCfg ); meterEstimator.Start(); meterEstimator.Log() << "Processing drums-electronic-guit.wav" << std::endl; meterEstimator.Do( signal, extractedBeats, result ); meterEstimator.Stop(); CLAM::XMLStorage::Dump( result, "Meter", "drums-electronic-guit_Meter.xml"); CPPUNIT_ASSERT_EQUAL( inst.GetNumerator(), result.GetNumerator() ); CPPUNIT_ASSERT_EQUAL( inst.GetDenominator(), result.GetDenominator() ); } void test_elecpiano_drums_Ticks() { CLAM::RhythmDescription::Meter inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Meter/elecpiano-drums_Meter.xml" ); CLAM::Pulse extractedEvents; CLAM::Pulse extractedBeats; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/Data/elecpiano-drums.wav", cfg, extractedEvents, extractedBeats ); CLAM::Audio signal; LoadAudio( mPathToTests + "/Data/elecpiano-drums.wav", signal ); CLAM::RhythmDescription::Meter result; CLAM::RhythmDescription::MeterEstimator meterEstimator; meterEstimator.Configure( mMeterEstCfg ); meterEstimator.Start(); meterEstimator.Log() << "Processing elecpiano-drums.wav" << std::endl; meterEstimator.Do( signal, extractedBeats, result ); meterEstimator.Stop(); CLAM::XMLStorage::Dump( result, "Meter", "elecpiano-drums_Meter.xml"); CPPUNIT_ASSERT_EQUAL( inst.GetNumerator(), result.GetNumerator() ); CPPUNIT_ASSERT_EQUAL( inst.GetDenominator(), result.GetDenominator() ); } void test_test1_Ticks() { CLAM::RhythmDescription::Meter inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Meter/test1_Meter.xml" ); CLAM::Pulse extractedEvents; CLAM::Pulse extractedBeats; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/Data/test1.wav", cfg, extractedEvents, extractedBeats ); CLAM::Audio signal; LoadAudio( mPathToTests + "/Data/test1.wav", signal ); CLAM::RhythmDescription::Meter result; CLAM::RhythmDescription::MeterEstimator meterEstimator; meterEstimator.Configure( mMeterEstCfg ); meterEstimator.Start(); meterEstimator.Log() << "Processing test1.wav" << std::endl; meterEstimator.Do( signal, extractedBeats, result ); meterEstimator.Stop(); CLAM::XMLStorage::Dump( result, "Meter", "test1_Meter.xml"); CPPUNIT_ASSERT_EQUAL( inst.GetNumerator(), result.GetNumerator() ); CPPUNIT_ASSERT_EQUAL( inst.GetDenominator(), result.GetDenominator() ); } void test_test2_Ticks() { CLAM::RhythmDescription::Meter inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Meter/test2_Meter.xml" ); CLAM::Pulse extractedEvents; CLAM::Pulse extractedBeats; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/Data/test2.wav", cfg, extractedEvents, extractedBeats ); CLAM::Audio signal; LoadAudio( mPathToTests + "/Data/test2.wav", signal ); CLAM::RhythmDescription::Meter result; CLAM::RhythmDescription::MeterEstimator meterEstimator; meterEstimator.Configure( mMeterEstCfg ); meterEstimator.Start(); meterEstimator.Log() << "Processing test2.wav" << std::endl; meterEstimator.Do( signal, extractedBeats, result ); meterEstimator.Stop(); CLAM::XMLStorage::Dump( result, "Meter", "test2_Meter.xml"); CPPUNIT_ASSERT_EQUAL( inst.GetNumerator(), result.GetNumerator() ); CPPUNIT_ASSERT_EQUAL( inst.GetDenominator(), result.GetDenominator() ); } void test_test_Ticks() { CLAM::RhythmDescription::Meter inst; CLAM::XMLStorage::Restore( inst, mPathToTests + "/Meter/test_Meter.xml" ); CLAM::Pulse extractedEvents; CLAM::Pulse extractedBeats; CLAM::TickExtractorConfig cfg; cfg.SetOnsetDetection( CLAM::OnsetDetectMethod( mOnsetDetectionAlgorithm ) ); CLAM::ExtractTicksSequence( mPathToTests + "/Data/test.wav", cfg, extractedEvents, extractedBeats ); CLAM::Audio signal; LoadAudio( mPathToTests + "/Data/test.wav", signal ); CLAM::RhythmDescription::Meter result; CLAM::RhythmDescription::MeterEstimator meterEstimator; meterEstimator.Configure( mMeterEstCfg ); meterEstimator.Start(); meterEstimator.Log() << "Processing test.wav" << std::endl; meterEstimator.Do( signal, extractedBeats, result ); meterEstimator.Stop(); CLAM::XMLStorage::Dump( result, "Meter", "test_Meter.xml"); CPPUNIT_ASSERT_EQUAL( inst.GetNumerator(), result.GetNumerator() ); CPPUNIT_ASSERT_EQUAL( inst.GetDenominator(), result.GetDenominator() ); } }; } clam-1.4.0/test/FunctionalTests/Applications/MIRTests/RhythmDescriptionHelpers.cxx0000644000000000000000000000652210610720021027052 0ustar rootroot#include "RhythmDescriptionHelpers.hxx" #include "CLAM_Math.hxx" namespace CLAMTest { namespace RhythmDescriptionTests { void RhythmEventsB2B::DefaultInit() { } bool RhythmEventsB2B::IsValid() const { return HasRelativePath() && HasEvents(); } void TickSequence::DefaultInit() { } void TransientEventList::DefaultInit() { } bool TransientEventList::IsValid() const { return HasRelativePath() && HasEvents(); } void IOIHistogramB2B::DefaultInit() { } bool IOIHistogramB2B::IsValid() const { return HasRelativePath() && HasIOIHistogram(); } void EventListDifference::DefaultInit() { AddAll(); UpdateData(); SetAveragePositionDeviation( 0.0 ); SetAverageWeightDeviation( 0.0 ); SetMinTimePositionDeviation( 1e20 ); SetMaxTimePositionDeviation( 1e-20 ); SetMinWeightDeviation( 1e20 ); SetMaxWeightDeviation( 1e-20 ); SetLengthMatched( false ); } void EventListDifference::Compare( const CLAM::Array< CLAM::TimeIndex >& truth, const CLAM::Array< CLAM::TimeIndex >& yield ) { CLAM::Array< CLAM::TimeIndex >& diff = GetDifference(); if ( truth.Size() == yield.Size() ) SetLengthMatched( true ); CLAM::TSize size = std::min( truth.Size(), yield.Size() ); diff.Resize( size ); diff.SetSize( size ); CLAM::TData avgWDev = 0.0; CLAM::TData avgPDev = 0.0; for ( int i = 0; i < diff.Size(); i++ ) { CLAM::TData diffPosition = truth[i].GetPosition() - yield[i].GetPosition(); diff[i].SetPosition( diffPosition ); CLAM::TData diffWeight = truth[i].GetWeight() - yield[i].GetWeight(); diff[i].SetWeight( diffWeight ); avgWDev += diffWeight; avgPDev += diffPosition; if ( GetMinTimePositionDeviation() > fabs( diffPosition ) ) SetMinTimePositionDeviation( fabs(diffPosition ) ); if ( GetMaxTimePositionDeviation() < fabs( diffPosition ) ) SetMaxTimePositionDeviation( fabs( diffPosition ) ); if ( GetMinWeightDeviation() > fabs( diffWeight ) ) SetMinWeightDeviation( fabs(diffWeight ) ); if ( GetMaxWeightDeviation() < fabs( diffWeight ) ) SetMaxWeightDeviation( fabs( diffWeight ) ); } SetAveragePositionDeviation( avgPDev / CLAM::TData( size ) ); SetAverageWeightDeviation( avgWDev / CLAM::TData( size ) ); } void EventListDifference::CompareWithIdeal( const TickSequence& ideal, const CLAM::Array< CLAM::TimeIndex >& yield ) { CLAM::Array< CLAM::TimeIndex >& diff = GetDifference(); if ( ideal.GetTickSequence().Size() == yield.Size() ) SetLengthMatched( true ); CLAM::TSize size = std::min( ideal.GetTickSequence().Size(), yield.Size() ); diff.Resize( size ); diff.SetSize( size ); CLAM::TData avgWDev = 0.0; CLAM::TData avgPDev = 0.0; const CLAM::DataArray& truePositions = ideal.GetTickSequence(); for ( int i = 0; i < diff.Size(); i++ ) { CLAM::TData diffPosition = truePositions[i] - yield[i].GetPosition(); diff[i].SetPosition( diffPosition ); diff[i].SetWeight( 0.0 ); avgPDev += diffPosition; if ( GetMinTimePositionDeviation() > fabs( diffPosition ) ) SetMinTimePositionDeviation( fabs(diffPosition ) ); if ( GetMaxTimePositionDeviation() < fabs( diffPosition ) ) SetMaxTimePositionDeviation( fabs( diffPosition ) ); } SetAveragePositionDeviation( avgPDev / CLAM::TData( size ) ); SetAverageWeightDeviation( avgWDev / CLAM::TData( size ) ); } } } clam-1.4.0/test/FunctionalTests/FlowControlTests/0000755000000000000000000000000011344207076020531 5ustar rootrootclam-1.4.0/test/EfficiencyTests/0000755000000000000000000000000011344231441015171 5ustar rootrootclam-1.4.0/test/EfficiencyTests/CommonHelpers/0000755000000000000000000000000011344231441017744 5ustar rootrootclam-1.4.0/test/EfficiencyTests/CommonHelpers/FileEditor.py0000644000000000000000000000275110412474424022356 0ustar rootrootimport yaml import re class FileEditor: def assignNames(self,valuesList): return { 'Instruction Searching':valuesList[0], 'Reading Access':valuesList[1], 'Writing Access':valuesList[2], 'Searching Error':valuesList[3], 'Reading Error':valuesList[4], 'Writing Error':valuesList[5], 'Cicle Estimation':valuesList[6] } def modifyValuesList(self,costMap): keyList=costMap.keys() keyListLength=len(keyList) i=0; while i[\w ]+): (?P\d+)\n') for line in stream: match=eventExpr.search(line) if line=="---\n": return eventsMap if match==None: continue eventsMap[match.group('name')]=int(match.group('value')) return eventsMap def fileToMap(self,stream): testMap={} testNameExpr= re.compile(r'\'(?P[^ ]+Test::test[^ ]+)\':\n') for line in stream: match=testNameExpr.search(line) if match==None: continue testMap[match.group('name')]=self.buildEventsMap(stream) return testMap clam-1.4.0/test/EfficiencyTests/CommonHelpers/Cost.py0000644000000000000000000000473410412474424021243 0ustar rootrootimport string import re class Cost: _Ir=1 _Dr=2 _Dw=3 _I1mr=4 _D1mr=5 _D1mw=6 _I2mr=7 _D2mr=8 _D2mw=9 def fillLine(self,line): i=len(line) while i<10: line.append('0') i=i+1 return line def assignEventsPosition(self,stream): expression=re.compile("events: ") for line in stream: if expression.search(line)!=None: break eventsList=re.compile("\w+").findall(line) self._Ir=eventsList.index('Ir') self._Dr=eventsList.index('Dr') self._Dw=eventsList.index('Dw') self._I1mr=eventsList.index('I1mr') self._D1mr=eventsList.index('D1mr') self._D1mw=eventsList.index('D1mw') self._I2mr=eventsList.index('I2mr') self._D2mr=eventsList.index('D2mr') self._D2mw=eventsList.index('D2mw') return 1 def calculateSearchingErrors(self,line): #Searching errors= 10*SearchingErrorsL1 + 100*SearchingErrorsL2 return 10*int(line[self._I1mr])+100*int(line[self._I2mr]) def calculateReadingErrors(self,line): #Reading errors= 10*ReadingErrorsL1 + 100*ReadingErrorsL2 return 10*int(line[self._D1mr])+100*int(line[self._D2mr]) def calculateWritingErrors(self,line): #Reading errors= 10*WritingErrorsL1 + 100*WritingErrorsL2 return 10*int(line[self._D1mw])+100*int(line[self._D2mw]) def calculateCicles(self,line,totalErrors): #Cicles=Instructions+SearchingErrors+ReadingErrors+WritingErrors return int(line[1]) + totalErrors def calculateFunctionValuesList(self,line): instructions=int(line[self._Ir]) readingAccess=int(line[self._Dr]) writingAccess=int(line[self._Dw]) searchingErrors=self.calculateSearchingErrors(line) readingErrors=self.calculateReadingErrors(line) writingErrors=self.calculateWritingErrors(line) totalErrors=searchingErrors+readingErrors+writingErrors cicles=self.calculateCicles(line,totalErrors) return [instructions,readingAccess,writingAccess,searchingErrors,readingErrors,writingErrors,cicles] def calculateTestValuesList(self,testedFunctionsMap): keysList=testedFunctionsMap.keys() testValuesList=[0,0,0,0,0,0,0] for key in keysList: valuesLine=self.fillLine(testedFunctionsMap[key][1]) functionValuesList=self.calculateFunctionValuesList(valuesLine) i=0 while i<7: testValuesList[i]=testValuesList[i]+functionValuesList[i] i=i+1 return testValuesList def buildCostMap(self,testMap): keysList=testMap.keys() costMap={} for key in keysList: costMap[key]=self.calculateTestValuesList(testMap[key]) return costMap clam-1.4.0/test/EfficiencyTests/CommonHelpers/DataCollector.py0000644000000000000000000000352010412474424023043 0ustar rootrootimport yaml import datetime import sys from Parser import * from Cost import * from FileEditor import * #from DBImporter import * #from DBEditor import * class DataCollector: _server="localhost" _user="blashyrk" _password="wacken4ever" _dataBase="testsDB" def parsing(self,inputFile): parser=Parser() parser._testedFunctionsIdList=[] testMap=parser.completeParsing(inputFile) return testMap def buildCostMap(self,testMap): cost=Cost() costMap=cost.buildCostMap(testMap) return costMap def createYamlFile(self,costMap): fileEditor=FileEditor() costmap=fileEditor.modifyValuesList(costMap) fileEditor.mapToFile(costMap) def yamlToMap(self): fileEditor=FileEditor() yamlFile=open('YamlFile.yml','r') testMap=fileEditor.fileToMap(yamlFile) return testMap def testMapToDataBase(self,inputFile): ## dbi=DBImporter() ## dbe=DBEditor(self._server,self._user,self._password,self._dataBase) testingDate = datetime.date.today().strftime("%Y%m%d") testMap=self.parsing(inputFile) print "Test Map:" print testMap print " " costMap=self.buildCostMap(testMap) print "Cost Map:" print costMap self.createYamlFile(costMap) yamlFile=open('YamlFile.yml','r') print yamlFile.readlines() yamlFile.close() ## testMap=self.yamlToMap() ## ## dbi.importDate(testingDate,dbe) ## return dbi.costMapToDB(testMap,testingDate,dbe) ##print "We are Executing the callgrind collector :)" ##input = sys.argv[1] ##inputFile=open(input,'r') ##dataCollector=DataCollector() ##dataCollector.testMapToDataBase(inputFile) clam-1.4.0/test/EfficiencyTests/CommonHelpers/EfficiencyTest.cxx0000644000000000000000000000026510412474424023404 0ustar rootroot#include "EfficiencyTest.hxx" void EfficiencyTest::start() { for (int i=4000; i--; ) _testimony++; } void EfficiencyTest::stop() { for (int i=4000; i--; ) _testimony++; } clam-1.4.0/test/EfficiencyTests/CommonHelpers/DataCollectorTrigger.py0000644000000000000000000000037110412474424024370 0ustar rootrootimport sys import StringIO from DataCollector import * print "We are going to Execute the callgrind collector :)" input = sys.argv[1] inputFile=open(input,'r') dataCollector=DataCollector() dataCollector.testMapToDataBase(inputFile) clam-1.4.0/test/EfficiencyTests/CommonHelpers/EfficiencyTest.hxx0000644000000000000000000000037110610720021023372 0ustar rootroot#ifndef EfficiencyTest_hxx #define EfficiencyTest_hxx #include class EfficiencyTest : public CppUnit::TestFixture { unsigned _testimony; protected: void start(); void stop(); }; #endif//EfficiencyTest_hxx clam-1.4.0/test/EfficiencyTests/CommonHelpers/Parser.py0000644000000000000000000001143110412474424021557 0ustar rootrootimport re import string class Parser: _startCountingSymbol="EfficiencyTest::start()" _stopCountingSymbol="EfficiencyTest::stop()" _startCountingId = 0 _stopCountingId = 0 _foundLimits = 0 _functionValues = [] _symbolRe = r'^c?fn=\((?P\d+)\) (?P%s)\n' _startCountingRe = re.compile(_symbolRe % _startCountingSymbol) _stopCountingRe = re.compile(_symbolRe % _stopCountingSymbol) _testMethodRe = re.compile(_symbolRe % "[^ ]+Test::test[^ ]+") #_testedFunctionsIdList = [] #_cfnMap = {} ## 1st Parse def ExtractSymbolInformation(self,line, symbolPattern): """ Given a symbol pattern and a callgrind output line, returns a tuple of id and the symbol if there is a first ocurrence of the symbol. It returns None when it is not a first symbol usage or when the pattern doesn't match. """ match = re.compile(r'^c?fn=\((?P\d+)\) (?P'+symbolPattern+')\n').search(line) if (match == None): return None return (int(match.group('id')), match.group('symbol')) def FindLimitsId(self,line): """Given a line to check saves the id of the symbols for start and stop simbols if they are included. Returns 1 when any of them are found and None when not. """ pair = self.ExtractSymbolInformation(line,".*") if pair==None: return None if pair[1]==self._startCountingSymbol: self._startCountingId = pair[0] self._foundLimits = self._foundLimits+1; return 1 if pair[1]==self._stopCountingSymbol: self._stopCountingId = pair[0] self._foundLimits = self._foundLimits+1; return 1 def BuildSymbolMap(self,stream, symbolPattern) : """Build the symbol map. """ symbolMap = {} for line in stream: pair = self.ExtractSymbolInformation(line, symbolPattern) if pair != None: symbolMap[pair[0]] = pair[1] continue if self._foundLimits!=2: self.FindLimitsId(line) return symbolMap ###2nd Parse def IsStart(self,line): match = re.compile(r'^cfn=\((?P\d+)\)').search(line) if match == None: return 0 functionId = int(match.group('id')) if functionId != self._startCountingId: return 0 return 1 def IsStop(self,line): match = re.compile(r'^cfn=\((?P\d+)\)').search(line) if match == None: return -1 functionId = int(match.group('id')) if functionId != self._stopCountingId: return 0 return 1 def createFunctionName(self,functionNumber): decimal = ""; if functionNumber<10: decimal = "0"; return decimal+str(functionNumber); def takeFunctionValues(self,stream): ## print 'taking function values' self._functionValues = [] for line in stream: ## print line if re.compile("([\*] |[\+-]?\d+ )+").search(line) == None: return line lineValues = re.compile("([\*]|[\+-]?\d+)").findall(line) self._functionValues.append(lineValues) ## print 'end taking values' return line def BuildTestedFunctionsMap(self,stream): ## print 'building tested function map' functionNumber = 0 flag=0 testedFunctionsMap={} for line in stream: ## print line match = re.compile(r'^cfn=\((?P\d+)\)').search(line) if match == None: continue functionId = int(match.group('id')) if functionId == self._stopCountingId: return testedFunctionsMap while flag==0: functionNumber = functionNumber+1 functionName=self.createFunctionName(functionNumber) flag=self.IsStop(self.takeFunctionValues(stream)) testedFunctionsMap[functionName] = self._functionValues if flag==1: return testedFunctionsMap return None def FindStartCounting(self,stream): ## print 'find start counting' for line in stream: ## print line if re.compile("cfn=\("+str(self._startCountingId)+"\)").search(line) != None: return 1 return 0 def FindTest(self,stream,symbolMap): ## print 'Finding test' for line in stream: match = re.compile(r'^fn=\((?P\d+)\)').search(line) if match == None: continue functionId = int(match.group('id')) if symbolMap.has_key(functionId): return functionId return 0 def BuildTestMap(self,stream,symbolMap): testedFunctionsMap = {} TestMap = {} ## print self._startCountingId ## print self._stopCountingId while 1: functionId = self.FindTest(stream,symbolMap) if functionId == 0: continue ## print functionId functionName = symbolMap[functionId] del symbolMap[functionId] if self.FindStartCounting(stream) == 0: break testedFunctionsMap = self.BuildTestedFunctionsMap(stream) if testedFunctionsMap == None: break TestMap[functionName] = testedFunctionsMap if symbolMap == {}:break return TestMap #Parsing Complete def completeParsing(self,stream): symbolMap=self.BuildSymbolMap(stream,"[^ ]+Test::test[^ ]+") ## print symbolMap stream.seek(0) testMap=self.BuildTestMap(stream,symbolMap) ## print testMap return testMap clam-1.4.0/test/EfficiencyTests/README.txt0000644000000000000000000000030207707207245016677 0ustar rootrootThis directory contains test that logs the efficiency of certain parts of CLAM source. TODO: Tests here should fullfill a log protocol (to be determined) so the web interface should read it. clam-1.4.0/test/EfficiencyTests/SegmentXmlLoadTest.cxx0000644000000000000000000000212310412473721021442 0ustar rootroot #include #include "cppUnitHelper.hxx" #include "EfficiencyTest.hxx" #include "Segment.hxx" #include "XMLStorage.hxx" #include #include namespace CLAMTest { class SegmentXmlLoadEfficiencyTest; CPPUNIT_TEST_SUITE_REGISTRATION( SegmentXmlLoadEfficiencyTest ); class SegmentXmlLoadEfficiencyTest : public EfficiencyTest { public: CPPUNIT_TEST_SUITE( SegmentXmlLoadEfficiencyTest ); // CPPUNIT_TEST( testPathToFiles ); CPPUNIT_TEST( testLoadSegment); CPPUNIT_TEST_SUITE_END(); std::string mPathToTestData; public: // TestFixture interface void setUp() { mPathToTestData = GetTestDataDirectory(); } void tearDown() { } private: /* void testPathToFiles() { std::string msg = "Cound't open this file: " + mPathToTestData+"sine.wav"; CPPUNIT_ASSERT_MESSAGE(msg, helperFileExist(mPathToTestData+"sine.wav")); } */ void testLoadSegment() { start(); CLAM::Segment inputSegment; CLAM::XMLStorage::Restore( inputSegment, mPathToTestData+"/SMSAnalysisTests/sweep_segment.xml" ); stop(); } }; } // namespace CLAMTest clam-1.4.0/test/Visualization/0000755000000000000000000000000011344231434014745 5ustar rootrootclam-1.4.0/test/Visualization/StdioSpectrumPresentation.hxx0000644000000000000000000000224010610720021022663 0ustar rootroot#ifndef __STDIOSPECTRUMPRESENTATION__ #define __STDIOSPECTRUMPRESENTATION__ #include "Presentation.hxx" #include "Array.hxx" #include "DataTypes.hxx" #include "Slotv1.hxx" namespace CLAMVM { using SigSlot::Slotv1; using CLAM::DataArray; using CLAM::TData; class SpectrumModel; class StdioSpectrumPresentation : public Presentation { // attributes private: DataArray mBinsMagnitude; DataArray mBinsPhase; TData mSpectralRange; // Implementation details protected: // callback methods to be called by the view virtual void OnNewMagBins( const DataArray& array ); virtual void OnNewPhaseBins( const DataArray& array ); virtual void OnNewSpecRng( TData specRange ); public: // slots Slotv1 SetMagnitudeBins; Slotv1 SetPhaseBins; Slotv1 SetSpectralRange; StdioSpectrumPresentation(); virtual ~StdioSpectrumPresentation(); virtual void AttachTo( SpectrumModel& ); virtual void Detach(); void Show(); void Hide(); }; } #endif // StdioSpectrumPresentation.hxx clam-1.4.0/test/Visualization/TestFDFilterController.cxx0000644000000000000000000000457110610720021022031 0ustar rootroot#include "Err.hxx" #include "FDFilterGen.hxx" #include "FDFilterController.hxx" #include "DummyFDFWidget.hxx" #include "Assert.hxx" #include using CLAM::Err; using CLAM::FDFilterGen; using CLAM::FDFilterGenConfig; using CLAMVM::FDFilterController; using CLAMVM::DummyFDFWidget; void TestBasicUse() { FDFilterGenConfig cfg; cfg.SetSpectralRange( 22050 ); FDFilterController controller; DummyFDFWidget widget; FDFilterGen filter; filter.Configure( cfg ); filter.Start(); controller.BindTo( filter ); widget.AttachTo( controller ); filter.Stop(); } void TestUseCase_ValueSending() { FDFilterGenConfig cfg; cfg.SetSpectralRange( 22050 ); FDFilterController controller; DummyFDFWidget widget; FDFilterGen filter; filter.Configure( cfg ); filter.Start(); controller.BindTo( filter ); widget.AttachTo( controller ); widget.SendGain.Emit( -25 ); controller.Update(); CLAM_ASSERT( filter.Gain.GetLastValue() == -25, "Filter did not receive gain value!" ); widget.SendLowCutoff.Emit( 300 ); controller.Update(); CLAM_ASSERT( filter.LowCutOff.GetLastValue() == 300 , "Filter did not receive low cutoff freq!" ); widget.SendHighCutoff.Emit( 1600 ); controller.Update(); CLAM_ASSERT( filter.HighCutOff.GetLastValue() == 1600, "Filter did not receive high cutoff freq!" ); widget.SendStopBand.Emit( -3 ); controller.Update(); CLAM_ASSERT( filter.StopBandSlope.GetLastValue() == -3, "Filter did not receive stop band slope!"); widget.SendPassBand.Emit( 3 ); controller.Update(); CLAM_ASSERT( filter.PassBandSlope.GetLastValue() == 3, "Filter did not receive pass band slope!"); filter.Stop(); } int main( int argc, char** argv ) { std::cout << "FDFilterController Test" << std::endl; try { TestBasicUse(); std::cout << "Basic Use Case test PASSED!" << std::endl; TestUseCase_ValueSending(); std::cout << "Use Case test: Value Sending PASSED!" << std::endl; } catch ( CLAM::Err& e ) { std::cerr << "A CLAM controlled error has occured" << std::endl; e.Print(); std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( std::exception& e ) { std::cerr << "An standard library error has occured" << std::endl; std::cerr << e.what() << std::endl; std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( ... ) { std::cerr << "An unknown error has occured!" << std::endl; return -1; } return 0; } clam-1.4.0/test/Visualization/TestFl_SpectrumAnalyzer.cxx0000644000000000000000000001707310610720021022260 0ustar rootroot#include "Spectrum.hxx" #include "LogMagSpectrumAdapter.hxx" #include "Fl_SpectrumAnalyzer.hxx" #include "XMLStorage.hxx" #include "Err.hxx" #include "WidgetTKWrapper.hxx" #include "WindowedSpectrumGenerator.hxx" #include "Audio.hxx" #include #include #include using CLAMTest::WindowedSpectrumGeneratorConfig; using CLAMTest::WindowedSpectrumGenerator; using CLAM::Spectrum; using CLAMVM::WidgetTKWrapper; using CLAMVM::LogMagSpectrumAdapter; using CLAMVM::Fl_SpectrumAnalyzer; using CLAM::XMLStorage; static const char* sPathToData= "./Datasets/"; bool TestKnownSineFreqUseCase( LogMagSpectrumAdapter& view, Fl_SpectrumAnalyzer& presentation ) { int i,Size=1024; float SampleRate=8000.0; int numIterations = 1; // Audio creation CLAM::Audio myaudio; myaudio.SetSize( Size ); for (i=0;i #include #include using CLAM::SpectralPeakArray; using CLAM::XMLStorage; using CLAMVM::SpectralPeakArrayAdapter; using CLAMVM::StdioSpectralPeakArrayPresentation; static const char* sPathToData = "./Datasets/"; bool TestBasicUseCase( SpectralPeakArrayAdapter& view, StdioSpectralPeakArrayPresentation& presentation ) { XMLStorage x; SpectralPeakArray specPeakArrayObj; std::string filename = "SpectralPeakArray.xml"; std::string pathToFile = sPathToData; pathToFile+=filename; x.Restore( specPeakArrayObj, pathToFile ); view.BindTo( specPeakArrayObj ); view.Publish(); presentation.Show(); return true; } int main( int argc, char** argv ) { try { SpectralPeakArrayAdapter view; StdioSpectralPeakArrayPresentation presentation; presentation.AttachTo( view ); std::cerr << "BASIC SPECTRAL PEAK ARRAY USE CASE TEST LAUNCHED" << std::endl; if ( !TestBasicUseCase( view, presentation ) ) std::cerr << "Basic Use case Test...... FAILED!" << std::endl; else std::cerr << "Basic Use case Test...... Passed!" << std::endl; } catch ( CLAM::Err& e ) { std::cerr << "A CLAM controlled error has occured" << std::endl; e.Print(); std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( std::exception& e ) { std::cerr << "An standard library error has occured" << std::endl; std::cerr << e.what() << std::endl; std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( ... ) { std::cerr << "An unknown error has occured!" << std::endl; return -1; } return 0; } clam-1.4.0/test/Visualization/TestAudioView.cxx0000644000000000000000000000306410610720021020216 0ustar rootroot#include "Audio.hxx" #include "AudioAdapter.hxx" #include "XMLStorage.hxx" #include "StdioAudioPresentation.hxx" #include "Err.hxx" #include #include using CLAM::Audio; using CLAM::XMLStorage; using CLAMVM::AudioAdapter; using CLAMVM::StdioAudioPresentation; static const char* sPathToData="./Datasets/"; bool TestBasicUseCase( AudioAdapter& view, StdioAudioPresentation& presentation ) { XMLStorage x; Audio audioObj; std::string filename = "Audio.xml"; std::string pathToFile = sPathToData; pathToFile+=filename; x.Restore( audioObj, pathToFile ); // View and Presentation now talk with each other view.BindTo( audioObj ); view.Publish(); presentation.Show(); return true; } int main( int argc, char** argv ) { AudioAdapter view; StdioAudioPresentation presentation; presentation.AttachTo( view ); try { if ( !TestBasicUseCase( view, presentation) ) std::cerr << "Basic Use case Test...... FAILED!" << std::endl; else std::cerr << "Basic Use case Test...... Passed!" << std::endl; } catch ( CLAM::Err& e ) { std::cerr << "A CLAM controlled error has occured" << std::endl; e.Print(); std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( std::exception& e ) { std::cerr << "An standard library error has occured" << std::endl; std::cerr << e.what() << std::endl; std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( ... ) { std::cerr << "An unknown error has occured!" << std::endl; return -1; } return 0; } clam-1.4.0/test/Visualization/StdioSpectralPeakArrayPresentation.hxx0000644000000000000000000000161310610720021024441 0ustar rootroot#ifndef __STDIOSPECTRALPEAKARRAYPRESENTATION__ #define __STDIOSPECTRALPEAKARRAYPRESENTATION__ #include "Presentation.hxx" #include "Array.hxx" #include "Partial.hxx" #include "DataTypes.hxx" #include "Slotv1.hxx" namespace CLAMVM { using SigSlot::Slotv1; using CLAM::Array; class SpectralPeaksModel; class StdioSpectralPeakArrayPresentation : public Presentation { private: Array mPartialsToDraw; protected: // callback methods to be called by the view virtual void OnNewPartials( const Array& array ); public: Slotv1& > SetPartials; StdioSpectralPeakArrayPresentation(); virtual ~StdioSpectralPeakArrayPresentation(); virtual void AttachTo( SpectralPeaksModel& ); virtual void Detach(); void Show(); void Hide(); }; } #endif // StdioSpectralPeakArrayPresentation.hxx clam-1.4.0/test/Visualization/TestFl_Spectrum.cxx0000644000000000000000000001700110610720021020541 0ustar rootroot#include "Spectrum.hxx" #include "SpectrumConfig.hxx" #include "LogMagSpectrumAdapter.hxx" #include "FLTK/Fl_Spectrum.hxx" #include "XMLStorage.hxx" #include "Err.hxx" #include "WidgetTKWrapper.hxx" #include "WindowedSpectrumGenerator.hxx" #include "Audio.hxx" #include #include #include using CLAMTest::WindowedSpectrumGeneratorConfig; using CLAMTest::WindowedSpectrumGenerator; using CLAM::Spectrum; using CLAMVM::WidgetTKWrapper; using CLAMVM::LogMagSpectrumAdapter; using CLAMVM::Fl_Spectrum; using CLAM::XMLStorage; static const char* sPathToData= "../../../../../CLAM-TestData/spectralData/"; bool TestKnownSineFreqUseCase( LogMagSpectrumAdapter& view, Fl_Spectrum& presentation ) { int i,Size=1024; float SampleRate=8000.0; int numIterations = 1; // Audio creation CLAM::Audio myaudio; myaudio.SetSize( Size ); for (i=0;i namespace CLAMVM { DummyFDFWidget::DummyFDFWidget() { ReceiveLowCutoffRange.Wrap( this, &DummyFDFWidget::_OnNewLowCutoffRange ); ReceiveHighCutoffRange.Wrap( this, &DummyFDFWidget::_OnNewHighCutoffRange ); ReceiveGainRange.Wrap( this, &DummyFDFWidget::_OnNewGainRange ); } DummyFDFWidget::~DummyFDFWidget() { } void DummyFDFWidget::Show() { } void DummyFDFWidget::Hide( ) { } void DummyFDFWidget::AttachTo( ProcessingInControlSet& cs ) { InputControlModel& lcm = cs.Retrieve( "Low Cutoff Frequency"); InputControlModel& hcm = cs.Retrieve( "High Cutoff Frequency"); InputControlModel& gcm = cs.Retrieve( "Gain" ); InputControlModel& sbcm = cs.Retrieve( "Stop Band Slope" ); InputControlModel& pbcm = cs.Retrieve( "Pass Band Slope" ); lcm.ValueRangePublished.Connect( ReceiveLowCutoffRange ); hcm.ValueRangePublished.Connect( ReceiveHighCutoffRange ); gcm.ValueRangePublished.Connect( ReceiveGainRange ); SendGain.Connect( gcm.UpdateValue ); SendLowCutoff.Connect( lcm.UpdateValue ); SendHighCutoff.Connect( hcm.UpdateValue ); SendStopBand.Connect( sbcm.UpdateValue ); SendPassBand.Connect( pbcm.UpdateValue ); } void DummyFDFWidget::Detach() { } void DummyFDFWidget::_OnNewLowCutoffRange( CLAM::TControlData min, CLAM::TControlData max ) { std::cout << "New low cutoff range:" << std::endl; std::cout << "\t + { " << min << ", " << max << std::endl; } void DummyFDFWidget::_OnNewHighCutoffRange( CLAM::TControlData min, CLAM::TControlData max ) { std::cout << "New high cutoff range:" << std::endl; std::cout << "\t + { " << min << ", " << max << std::endl; } void DummyFDFWidget::_OnNewGainRange( CLAM::TControlData min, CLAM::TControlData max ) { std::cout << "New gain range:" << std::endl; std::cout << "\t + { " << min << ", " << max << std::endl; } } clam-1.4.0/test/Visualization/TestFl_Audio.cxx0000644000000000000000000000672610610720021020014 0ustar rootroot#include "Audio.hxx" #include "AudioAdapter.hxx" #include "XMLStorage.hxx" #include "FLTK/Fl_Audio.hxx" #include "Err.hxx" #include #include #include #include "CLAM_Math.hxx" #include "OSDefines.hxx" #include "WidgetTKWrapper.hxx" #include "AudioFileIn.hxx" #include using CLAM::Err; using CLAM::Audio; using CLAM::XMLStorage; using CLAM::AudioFileIn; using CLAM::AudioFileConfig; using CLAM::EAudioFileType; using CLAMVM::AudioAdapter; using CLAMVM::Fl_Audio; using CLAMVM::WidgetTKWrapper; static const char* sPathToData="./Datasets/"; static std::string sFilename; static bool sNoArgs; void CreateDummyAudioObject( Audio& audioObj ) { const float srate = 44100; const float freq = 440; const float amp = 0.745f; const int n = 4000; float deltaphi = (2 * M_PI * freq)/srate; // A = sin ( 2*pi*f*n/sr ) audioObj.SetSampleRate( 8000 ); audioObj.SetBeginTime( 0 ); audioObj.SetEndTime( float(n)/srate ); audioObj.SetSize( n ); float phi = 0.0; for ( int i = 0; i < n; i++ ) { audioObj.GetBuffer()[i] = amp * cos( phi ); phi += deltaphi; } } bool LoadAudioObjectFromFile( Audio& obj ) throw ( Err ) { AudioFileIn fileLoader; AudioFileConfig loaderConfig; loaderConfig.SetFilename( sFilename ); // loaderConfig.SetChannels( 2 ); loaderConfig.SetFiletype( EAudioFileType::eWave ); fileLoader.Configure( loaderConfig ); fileLoader.Start(); obj.SetSize( fileLoader.Size() ); fileLoader.Do( obj ); obj.SetSampleRate( fileLoader.SampleRate() ); return true; } bool TestBasicUseCase( AudioAdapter& view, Fl_Audio& presentation ) throw ( Err ) { XMLStorage x; Audio audioObj; // TODO: Ask David //std::string filename = "Audio_2.xml"; //std::string pathToFile = sPathToData; //pathToFile+=filename; //x.Restore( audioObj, pathToFile ); if ( sNoArgs ) CreateDummyAudioObject( audioObj ); else { if (!LoadAudioObjectFromFile( audioObj ) ) return false; } std::cout << "Dummy audio Object created" << std::endl; // View and Presentation now talk with each other view.BindTo( audioObj ); view.Publish(); presentation.Show(); WidgetTKWrapper& tk = WidgetTKWrapper::GetWrapperFor("FLTK"); tk.Run(); return true; } int main( int argc, char** argv ) { AudioAdapter view; Fl_Audio presentation(100,100,640,480, "An Audio Presentation"); sNoArgs = false; const char* strfile = fl_file_chooser( "Please, select a .wav file", "*.wav", NULL ); if ( strfile != NULL ) sFilename = strfile; else // no args supplied { sNoArgs = true; std::cout << "No args provided, displayed audio will be generated" << std::endl; } presentation.AttachTo( view ); try { if ( !TestBasicUseCase( view, presentation) ) std::cerr << "Basic Use case Test...... FAILED!" << std::endl; else std::cerr << "Basic Use case Test...... Passed!" << std::endl; } catch ( CLAM::Err& e ) { std::cerr << "A CLAM controlled error has occured" << std::endl; e.Print(); std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( std::exception& e ) { std::cerr << "An standard library error has occured" << std::endl; std::cerr << e.what() << std::endl; std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( ... ) { std::cerr << "An unknown error has occured!" << std::endl; return -1; } return 0; } clam-1.4.0/test/Visualization/TestSpectrumView.cxx0000644000000000000000000001022310610720021020752 0ustar rootroot#include "Spectrum.hxx" #include "LogMagSpectrumAdapter.hxx" #include "StdioSpectrumPresentation.hxx" #include "XMLStorage.hxx" #include "Err.hxx" #include #include #include using CLAM::Spectrum; using CLAMVM::LogMagSpectrumAdapter; using CLAMVM::StdioSpectrumPresentation; using CLAM::XMLStorage; static const char* sPathToData= "./Datasets/"; bool TestPureComplexUseCase(LogMagSpectrumAdapter& view, StdioSpectrumPresentation& presentation ) { XMLStorage x; Spectrum specObj; std::string filename = "SpectrumOnlyComplex.xml"; std::string pathToFile = sPathToData; pathToFile+=filename; x.Restore( specObj, pathToFile ); // Spectrum has been incorporated into the system view.BindTo( specObj ); view.Publish(); presentation.Show(); return true; } bool TestPurePolarUseCase(LogMagSpectrumAdapter& view, StdioSpectrumPresentation& presentation) { XMLStorage x; Spectrum specObj; std::string filename = "SpectrumOnlyPolar.xml"; std::string pathToFile = sPathToData; pathToFile+=filename; x.Restore( specObj, pathToFile ); // Spectrum has been incorporated into the system view.BindTo( specObj ); view.Publish(); presentation.Show(); return true; } bool TestPureBPFUseCase( LogMagSpectrumAdapter& view, StdioSpectrumPresentation& presentation ) { XMLStorage x; Spectrum specObj; std::string filename = "SpectrumOnlyBPF.xml"; std::string pathToFile = sPathToData; pathToFile+=filename; x.Restore( specObj, pathToFile ); // Spectrum has been incorporated into the system view.BindTo( specObj ); view.Publish(); presentation.Show(); return true; } bool TestBasicUseCase( LogMagSpectrumAdapter& view, StdioSpectrumPresentation& presentation ) { XMLStorage x; Spectrum specObj; std::string filename = "Spectrum.xml"; std::string pathToFile = sPathToData; pathToFile+=filename; x.Restore( specObj, pathToFile ); // Spectrum has been incorporated into the system view.BindTo( specObj ); view.Publish(); presentation.Show(); return true; } int main( int argc, char** argv ) { try { LogMagSpectrumAdapter view; StdioSpectrumPresentation presentation; presentation.AttachTo( view ); std::cerr << "BASIC SPECTRUM VIEW USE CASE TEST LAUNCHED" << std::endl; if ( !TestBasicUseCase( view, presentation ) ) std::cerr << "Basic Use case Test...... FAILED!" << std::endl; else std::cerr << "Basic Use case Test...... Passed!" << std::endl; std::cerr << "ONLY COMPLEX BUFFER ON SPECTRUM OBJECT SPECTRUM VIEW USE CASE TEST LAUNCHED" << std::endl; if ( !TestPureComplexUseCase( view, presentation ) ) std::cerr << "Observing spectrum with only complex buffer use case Test...... FAILED!" << std::endl; else std::cerr << "Observing spectrum with only complex buffer use case Test...... Passed!" << std::endl; std::cerr << "ONLY POLAR BUFFER ON SPECTRUM OBJECT SPECTRUM VIEW USE CASE TEST LAUNCHED" << std::endl; if ( !TestPurePolarUseCase( view, presentation ) ) std::cerr << "Observing spectrum with only polar buffer use case Test...... FAILED!" << std::endl; else std::cerr << "Observing spectrum with only polar buffer use case Test...... Passed!" << std::endl; std::cerr << "ONLY BPF BUFFERS ON SPECTRUM OBJECT SPECTRUM VIEW USE CASE TEST LAUNCHED" << std::endl; if ( !TestPureBPFUseCase( view, presentation ) ) std::cerr << "Observing spectrum with only BPF buffers use case Test...... FAILED!" << std::endl; else std::cerr << "Observing spectrum with only BPF buffers use case Test...... Passed!" << std::endl; } catch ( CLAM::Err& e ) { std::cerr << "A CLAM controlled error has occured" << std::endl; e.Print(); std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( std::exception& e ) { std::cerr << "An standard library error has occured" << std::endl; std::cerr << e.what() << std::endl; std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( ... ) { std::cerr << "An unknown error has occured!" << std::endl; return -1; } return 0; } clam-1.4.0/test/Visualization/StdioAudioPresentation.cxx0000644000000000000000000000413410610720021022121 0ustar rootroot#include "StdioAudioPresentation.hxx" #include "AudioModel.hxx" #include #include namespace CLAMVM { StdioAudioPresentation::StdioAudioPresentation() : mMaximum( 0 ), mMinimum( 0 ), mAudioLen( 0 ), mAudioStart( 0 ), mSampleRate( 0 ) { SetSamples.Wrap( this, &StdioAudioPresentation::OnNewSamples ); SetDuration.Wrap( this, &StdioAudioPresentation::OnNewDuration ); SetStartTime.Wrap( this, &StdioAudioPresentation::OnNewStartTime ); SetSampleRate.Wrap( this, &StdioAudioPresentation::OnNewSampleRate ); } StdioAudioPresentation::~StdioAudioPresentation() { } void StdioAudioPresentation::Show() { std::cout << "DATA RETRIEVED:" << std::endl; std::cout << "Maximum sample value: " << mMaximum << std::endl; std::cout << "Minimum sample value: " << mMinimum << std::endl; std::cout << "Audio length: " << mAudioLen << std::endl; std::cout << "Audio start time: " << mAudioStart << std::endl; std::cout << "Sample rate: " << mSampleRate << std::endl; std::cout << "END OF DATA RETRIEVED SO FAR" << std::endl; } void StdioAudioPresentation::Hide() { } void StdioAudioPresentation::AttachTo( AudioModel& model ) { // Here we go! model.SamplesPublished.Connect( SetSamples ); model.DurationPublished.Connect( SetDuration ); model.StartTimePublished.Connect( SetStartTime ); model.SampleRatePublished.Connect( SetSampleRate ); } void StdioAudioPresentation::Detach( ) { SetSamples.Unbind(); SetDuration.Unbind(); SetStartTime.Unbind(); SetSampleRate.Unbind(); } void StdioAudioPresentation::OnNewSamples( const DataArray& array ) { mMaximum = *std::max_element( array.GetPtr(), array.GetPtr()+array.Size() ); mMinimum = *std::min_element( array.GetPtr(), array.GetPtr()+array.Size() ); } void StdioAudioPresentation::OnNewDuration( TTime secs ) { mAudioLen = secs; } void StdioAudioPresentation::OnNewStartTime( TTime secs ) { mAudioStart = secs; } void StdioAudioPresentation::OnNewSampleRate( TData rate ) { mSampleRate = rate; } } clam-1.4.0/test/Visualization/StdioSpectrumPresentation.cxx0000644000000000000000000000470210610720021022663 0ustar rootroot#include "StdioSpectrumPresentation.hxx" #include "SpectrumModel.hxx" #include #include namespace CLAMVM { StdioSpectrumPresentation::StdioSpectrumPresentation() : mSpectralRange( 22050 ) { SetMagnitudeBins.Wrap( this, &StdioSpectrumPresentation::OnNewMagBins ); SetPhaseBins.Wrap( this, &StdioSpectrumPresentation::OnNewPhaseBins ); SetSpectralRange.Wrap( this, &StdioSpectrumPresentation::OnNewSpecRng ); } StdioSpectrumPresentation::~StdioSpectrumPresentation() { } void StdioSpectrumPresentation::Show() { std::cout << "DATA RETRIEVED:" << std::endl; std::cout << "Highest magnitude value (dB): "; std::cout << *std::max_element(mBinsMagnitude.GetPtr(),mBinsMagnitude.GetPtr()+mBinsMagnitude.Size() ); std::cout << std::endl; std::cout << "Lowest magnitude value (dB): "; std::cout << *std::min_element(mBinsMagnitude.GetPtr(),mBinsMagnitude.GetPtr()+mBinsMagnitude.Size() ); std::cout << std::endl; std::cout << "Highest phase angle ( radians ):"; std::cout << *std::max_element( mBinsPhase.GetPtr(),mBinsPhase.GetPtr()+mBinsPhase.Size() ); std::cout << std::endl; std::cout << "Lowest phase angle ( radians ):"; std::cout << *std::max_element( mBinsPhase.GetPtr(),mBinsPhase.GetPtr()+mBinsPhase.Size() ); std::cout << std::endl; std::cout << "Spectral range :" << mSpectralRange << std::endl; } void StdioSpectrumPresentation::Hide() { } void StdioSpectrumPresentation::AttachTo( SpectrumModel& model ) { model.MagnitudePublished.Connect( SetMagnitudeBins ); model.PhasePublished.Connect( SetPhaseBins ); model.SpectralRangePublished.Connect( SetSpectralRange ); } void StdioSpectrumPresentation::Detach() { SetMagnitudeBins.Unbind(); SetPhaseBins.Unbind(); SetSpectralRange.Unbind(); } void StdioSpectrumPresentation::OnNewMagBins( const DataArray& array ) { mBinsMagnitude.Resize( array.Size() ); mBinsMagnitude.SetSize( array.Size() ); std::copy( array.GetPtr(), array.GetPtr() + array.Size(), mBinsMagnitude.GetPtr() ); } void StdioSpectrumPresentation::OnNewPhaseBins( const DataArray& array ) { mBinsPhase.Resize( array.Size() ); mBinsPhase.SetSize( array.Size() ); std::copy( array.GetPtr(), array.GetPtr() + array.Size(), mBinsPhase.GetPtr() ); } void StdioSpectrumPresentation::OnNewSpecRng( TData specRange ) { mSpectralRange = specRange; } } clam-1.4.0/test/Visualization/TestModelController/0000755000000000000000000000000011344207065020714 5ustar rootrootclam-1.4.0/test/Visualization/TestModelController/TestSources/0000755000000000000000000000000011344207065023177 5ustar rootrootclam-1.4.0/test/Visualization/TestModelController/TestSources/ModelController/0000755000000000000000000000000011344231433026277 5ustar rootrootclam-1.4.0/test/Visualization/TestModelController/TestSources/ModelController/TestUnit.cxx0000644000000000000000000000667210610720021030604 0ustar rootroot#include #include #include #include #include "TestCases.hxx" void PrintSuccessMessage( const char* tcname ) { std::cout << tcname << " passed" << std::endl; } void DecorateException( const char* tcname, CLAM::ErrAssertionFailed& e ) { std::cerr << tcname << " FAILED! due to ASSERTION FAILURE" << std::endl; e.Print(); } void DecorateException( const char* tcname, CLAM::Err& e ) { std::cerr << tcname << " FAILED! "; std::cerr << "due to a CLAM GENERIC EXCEPTION!" << std::endl; e.Print(); } void DecorateException( const char* tcname, std::exception& e ) { std::cerr << tcname << " FAILED! "; std::cerr << "due to a Standard Library GENERIC EXCEPTION!" << std::endl; std::cerr << "message: " << e.what() << std::endl; } void DecorateException( const char* tcname ) { std::cerr << tcname << " FAILED! "; std::cerr << "due to a UNKNOWN EXCEPTION"; } int main( int arc, char** argv ) { try { try { CLAMDraft::TestBindingProcessingAdapter(); PrintSuccessMessage( "TestBinding" ); } catch( CLAM::ErrAssertionFailed& e ) { DecorateException( "TestBinding", e ); } catch( CLAM::Err& e ) { DecorateException( "TestBinding", e ); } catch( std::exception& e ) { DecorateException( "TestBinding", e ); } catch( ... ) { DecorateException( "TestBinding" ); } try { CLAMDraft::TestAttachPresentationAdapter(); PrintSuccessMessage( "TestAttachPresentationAdapter" ); } catch( CLAM::ErrAssertionFailed& e ) { DecorateException( "TestAttachPresentationAdapter", e ); } catch( CLAM::Err& e ) { DecorateException( "TestAttachPresentationAdapter", e ); } catch( std::exception& e ) { DecorateException( "TestAttachPresentationAdapter", e ); } catch( ... ) { DecorateException( "TestAttachPresentationAdapter" ); } try { CLAMDraft::TestControlUpdating(); PrintSuccessMessage( "TestControlUpdating" ); } catch( CLAM::ErrAssertionFailed& e ) { DecorateException( "TestControlUpdating", e ); } catch( CLAM::Err& e ) { DecorateException( "TestControlUpdating", e ); } catch( std::exception& e ) { DecorateException( "TestControlUpdating", e ); } catch( ... ) { DecorateException( "TestControlUpdating" ); } try { CLAMDraft::TestSeveralControlsUpdating(); PrintSuccessMessage( "TestSeveralControlsUpdating" ); } catch( CLAM::ErrAssertionFailed& e ) { DecorateException( "TestSeveralControlsUpdating", e ); } catch( CLAM::Err& e ) { DecorateException( "TestSeveralControlsUpdating", e ); } catch( std::exception& e ) { DecorateException( "TestSeveralControlsUpdating", e ); } catch( ... ) { DecorateException( "TestSeveralControlsUpdating" ); } std::cout << "Unit test executed" << std::endl; } catch( CLAM::Err& e ) { std::cerr << "#####CLAM Exception Caught at " << __FILE__ << __LINE__ << "#####" << std::endl; std::cerr << "CLAM::Err Printing follows: " << std::endl; e.Print(); exit(-1); } catch( std::exception& e ) { std::cerr << "#####Standard Library Exception Caught at " << __FILE__ << __LINE__ << "#####" << std::endl; std::cerr << "CLAM::Err Printing follows: " << std::endl; std::cerr << e.what() << std::endl; exit(-1); } catch(...) { std::cerr << "#####Unknown Exception Caught at " << __FILE__ << __LINE__ << "#####" << std::endl; exit(-1); } return 0; } ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootclam-1.4.0/test/Visualization/TestModelController/TestSources/ModelController/ConcreteModelController.cxxclam-1.4.0/test/Visualization/TestModelController/TestSources/ModelController/ConcreteModelControlle0000644000000000000000000000106310610720021032616 0ustar rootroot#include "ConcreteModelController.hxx" #include namespace CLAMVM { ConcreteModelController::ConcreteModelController() { Prepare(); } ConcreteModelController::~ConcreteModelController() { } void ConcreteModelController::RegisterOutControls( ) { RegisterAs( &mOutCtl_1, "Control#1" ); RegisterAs( &mOutCtl_2, "Control#2" ); RegisterAs( &mOutCtl_3, "Control#3" ); RegisterAs( &mOutCtl_4, "Control#4" ); RegisterAs( &mOutCtl_5, "Control#5" ); RegisterAs( &mOutCtl_6, "Control#6" ); } } clam-1.4.0/test/Visualization/TestModelController/TestSources/ModelController/TestCases.hxx0000644000000000000000000000036710610720021030723 0ustar rootroot#ifndef __TESTCASES__ #define __TESTCASES__ namespace CLAMDraft { void TestBindingProcessingAdapter(); void TestAttachPresentationAdapter(); void TestControlUpdating(); void TestSeveralControlsUpdating(); } #endif // TestCases.hxx clam-1.4.0/test/Visualization/TestModelController/TestSources/ModelController/TestCases.cxx0000644000000000000000000000667310610720021030724 0ustar rootroot#include "TestCases.hxx" #include "ProcFeatSeveralControls.hxx" #include "ProcessingController.hxx" #include "FakeCompositeControlWidget.hxx" #include namespace CLAMDraft { using CLAMVM::ProcessingController; void TestBindingProcessingAdapter() { ProcFeatSeveralControls proc; ProcFeatSeveralControlsConfig procCfg; ProcessingController modCont; proc.Configure( procCfg ); CLAM_ASSERT( modCont.BindTo( proc ), "Binding has failed!"); } void TestAttachPresentationAdapter( ) { ProcFeatSeveralControls proc; ProcFeatSeveralControlsConfig procCfg; ProcessingController modCont; FakeCompositeControlWidget compoWidget; proc.Configure( procCfg ); modCont.BindTo( proc ); compoWidget.AttachTo( modCont ); } bool AssertTimesCalled( ProcFeatSeveralControls& stubProc, int expectedTimes ) { if ( stubProc.GetControlTimesCalled( 0 ) != expectedTimes ) return false; if ( stubProc.GetControlTimesCalled( 1 ) != expectedTimes ) return false; if ( stubProc.GetControlTimesCalled( 2 ) != expectedTimes ) return false; if ( stubProc.GetControlTimesCalled( 3 ) != expectedTimes ) return false; if ( stubProc.GetControlTimesCalled( 4 ) != expectedTimes ) return false; if ( stubProc.GetControlTimesCalled( 5 ) != expectedTimes ) return false; return true; } bool AssertValuesReceived( ProcFeatSeveralControls& stubProc, std::vector& values ) { if ( stubProc.GetControlLastValue( 0 ) != values[0] ) return false; if ( stubProc.GetControlLastValue( 1 ) != values[1] ) return false; if ( stubProc.GetControlLastValue( 2 ) != values[2] ) return false; if ( stubProc.GetControlLastValue( 3 ) != values[3] ) return false; if ( stubProc.GetControlLastValue( 4 ) != values[4] ) return false; if ( stubProc.GetControlLastValue( 5 ) != values[5] ) return false; return true; } void TestControlUpdating() { ProcFeatSeveralControls proc; ProcFeatSeveralControlsConfig procCfg; ProcessingController modCont; FakeCompositeControlWidget compoWidget; modCont.BindTo( proc ); compoWidget.AttachTo( modCont ); std::vector values; values.resize( 6 ); values[0] = 33.0f; values[1] = 21.0f; values[2] = 15.0f; values[3] = 100.0f; values[4] = 1000.0f; values[5] = 10000.0f; compoWidget.SendTheseValues( values ); modCont.Update(); CLAM_ASSERT( AssertTimesCalled( proc, 1 ), "Times called mismatch!" ); CLAM_ASSERT( AssertValuesReceived( proc, values ), "Values received mismatch!" ); } void TestSeveralControlsUpdating() { ProcFeatSeveralControls proc; ProcFeatSeveralControlsConfig procCfg; ProcessingController modCont; FakeCompositeControlWidget compoWidget; modCont.BindTo( proc ); compoWidget.AttachTo( modCont ); std::vector values; values.resize( 6 ); values[0] = 33.0f; values[1] = 21.0f; values[2] = 15.0f; values[3] = 100.0f; values[4] = 1000.0f; values[5] = 10000.0f; for ( int i = 0; i < 11; i++ ) { values[0]+=i; values[1]+=i; values[2]+=i; values[3]+=i; values[4]+=i; values[5]+=i; compoWidget.SendTheseValues( values ); modCont.Update(); } CLAM_ASSERT( AssertTimesCalled( proc, 11 ), "Times called mismatch!" ); CLAM_ASSERT( AssertValuesReceived( proc, values ), "Values received mismatch!" ); } } ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootclam-1.4.0/test/Visualization/TestModelController/TestSources/ModelController/ConcreteModelController.hxxclam-1.4.0/test/Visualization/TestModelController/TestSources/ModelController/ConcreteModelControlle0000644000000000000000000000163210610720021032620 0ustar rootroot#ifndef __CONCRETEMODELCONTROLLER__ #define __CONCRETEMODELCONTROLLER__ #include #include "ProcessingController.hxx" #include "ProcFeatSeveralControls.hxx" namespace CLAMVM { using CLAM::Processing; using CLAMDraft::ProcFeatSeveralControls; class ConcreteModelController : public ProcessingController { // attributes private: ControlAdapter mOutCtl_1; ControlAdapter mOutCtl_2; ControlAdapter mOutCtl_3; ControlAdapter mOutCtl_4; ControlAdapter mOutCtl_5; ControlAdapter mOutCtl_6; public: ConcreteModelController(); virtual ~ConcreteModelController(); virtual const char* GetClassName() const { return "ConcreteModelController"; } protected: virtual void RegisterOutControls(); }; } #endif // ConcreteModelController.hxx clam-1.4.0/test/Visualization/TestModelController/TestSources/ControlAdapter/0000755000000000000000000000000011344231433026114 5ustar rootrootclam-1.4.0/test/Visualization/TestModelController/TestSources/ControlAdapter/TestUnit.cxx0000644000000000000000000000666510610720021030423 0ustar rootroot#include #include #include #include #include "TestCases.hxx" void PrintSuccessMessage( const char* tcname ) { std::cout << tcname << " passed" << std::endl; } void DecorateException( const char* tcname, CLAM::ErrAssertionFailed& e ) { std::cerr << tcname << " FAILED! due to ASSERTION FAILURE" << std::endl; e.Print(); } void DecorateException( const char* tcname, CLAM::Err& e ) { std::cerr << tcname << " FAILED! "; std::cerr << "due to a CLAM GENERIC EXCEPTION!" << std::endl; e.Print(); } void DecorateException( const char* tcname, std::exception& e ) { std::cerr << tcname << " FAILED! "; std::cerr << "due to a Standard Library GENERIC EXCEPTION!" << std::endl; std::cerr << "message: " << e.what() << std::endl; } void DecorateException( const char* tcname ) { std::cerr << tcname << " FAILED! "; std::cerr << "due to a UNKNOWN EXCEPTION"; } int main( int arc, char** argv ) { try { try { CLAMDraft::TestBindingProcessingAdapter(); PrintSuccessMessage( "TestBinding" ); } catch( CLAM::ErrAssertionFailed& e ) { DecorateException( "TestBinding", e ); } catch( CLAM::Err& e ) { DecorateException( "TestBinding", e ); } catch( std::exception& e ) { DecorateException( "TestBinding", e ); } catch( ... ) { DecorateException( "TestBinding" ); } try { CLAMDraft::TestAttachPresentationAdapter(); PrintSuccessMessage( "TestAttachPresentationAdapter" ); } catch( CLAM::ErrAssertionFailed& e ) { DecorateException( "TestAttachPresentationAdapter", e ); } catch( CLAM::Err& e ) { DecorateException( "TestAttachPresentationAdapter", e ); } catch( std::exception& e ) { DecorateException( "TestAttachPresentationAdapter", e ); } catch( ... ) { DecorateException( "TestAttachPresentationAdapter" ); } try { CLAMDraft::TestControlUpdating(); PrintSuccessMessage( "TestControlUpdating" ); } catch( CLAM::ErrAssertionFailed& e ) { DecorateException( "TestControlUpdating", e ); } catch( CLAM::Err& e ) { DecorateException( "TestControlUpdating", e ); } catch( std::exception& e ) { DecorateException( "TestControlUpdating", e ); } catch( ... ) { DecorateException( "TestConrolUpdating" ); } try { CLAMDraft::TestSeveralControlsUpdating(); PrintSuccessMessage( "TestSeveralControlsUpdating" ); } catch( CLAM::ErrAssertionFailed& e ) { DecorateException( "TestSeveralControlsUpdating", e ); } catch( CLAM::Err& e ) { DecorateException( "TestSeveralControlsUpdating", e ); } catch( std::exception& e ) { DecorateException( "TestSeveralControlsUpdating", e ); } catch( ... ) { DecorateException( "TestSeveralControlsUpdating" ); } std::cout << "Unit test executed" << std::endl; } catch( CLAM::Err& e ) { std::cerr << "#####CLAM Exception Caught at " << __FILE__ << __LINE__ << "#####" << std::endl; std::cerr << "CLAM::Err Printing follows: " << std::endl; e.Print(); exit(-1); } catch( std::exception& e ) { std::cerr << "#####Standard Library Exception Caught at " << __FILE__ << __LINE__ << "#####" << std::endl; std::cerr << "CLAM::Err Printing follows: " << std::endl; std::cerr << e.what() << std::endl; exit(-1); } catch(...) { std::cerr << "#####Unknown Exception Caught at " << __FILE__ << __LINE__ << "#####" << std::endl; exit(-1); } return 0; } clam-1.4.0/test/Visualization/TestModelController/TestSources/ControlAdapter/TestCases.hxx0000644000000000000000000000035710610720021030537 0ustar rootroot#ifndef __TESTCASES__ #define __TESTCASES__ namespace CLAMDraft { void TestBindingProcessingAdapter(); void TestAttachPresentationAdapter(); void TestControlUpdating(); void TestSeveralControlsUpdating(); } #endif // TestCases.hxx clam-1.4.0/test/Visualization/TestModelController/TestSources/ControlAdapter/TestCases.cxx0000644000000000000000000000272610610720021030534 0ustar rootroot#include "TestCases.hxx" #include "SimpleProcessing.hxx" #include "ControlAdapter.hxx" #include "FakeControlWidget.hxx" namespace CLAMDraft { using CLAMVM::ControlAdapter; void TestBindingProcessingAdapter() { SimpleProcessing proc; SimpleProcessingConfig procCfg; ControlAdapter adap; proc.Configure( procCfg ); CLAM_ASSERT( adap.BindTo( proc.GetControl() ), "Binding Failed" ); } void TestAttachPresentationAdapter() { ControlAdapter adap; FakeControlWidget fakeWidget; fakeWidget.AttachTo( adap ); } void TestControlUpdating() { SimpleProcessing proc; SimpleProcessingConfig procCfg; ControlAdapter adap; FakeControlWidget fakeWidget; proc.Configure( procCfg ); adap.BindTo( proc.GetControl() ); adap.Publish(); fakeWidget.AttachTo( adap ); fakeWidget.SendValue.Emit( 10 ); adap.Update(); CLAM_ASSERT( proc.GetControl().GetLastValue() == 10 , "Value was not received by model object" ); } void TestSeveralControlsUpdating() { SimpleProcessing proc; SimpleProcessingConfig procCfg; ControlAdapter adap; FakeControlWidget fakeWidget; proc.Configure( procCfg ); adap.BindTo( proc.GetControl() ); fakeWidget.AttachTo( adap ); for ( int i = 0; i < 11; i++ ) { fakeWidget.SendValue.Emit( i ); } adap.Update(); CLAM_ASSERT( proc.GetControl().GetLastValue() == 10 , "Value was not received by model object" ); } } clam-1.4.0/test/Visualization/TestModelController/Stubs/0000755000000000000000000000000011344231433022010 5ustar rootrootclam-1.4.0/test/Visualization/TestModelController/Stubs/SimpleProcessing.cxx0000644000000000000000000000170610610720021026015 0ustar rootroot#include "SimpleProcessing.hxx" namespace CLAMDraft { void SimpleProcessingConfig::DefaultInit() { AddAll(); UpdateData(); } SimpleProcessing::SimpleProcessing() : mInControl( "InControl", this, &SimpleProcessing::InControl_cb ) { } SimpleProcessing::SimpleProcessing( const SimpleProcessingConfig& cfg ) : mInControl( "InControl", this, &SimpleProcessing::InControl_cb ) { Configure( cfg ); } SimpleProcessing::~SimpleProcessing() { } bool SimpleProcessing::Do() { return true; } bool SimpleProcessing::ConcreteConfigure( const ProcessingConfig& cfg ) { CopyAsConcreteConfig( mConfig, cfg ); return true; } bool SimpleProcessing::ConcreteStart() { // Control initialization? mInControl.DoControl( 0 ); return true; } bool SimpleProcessing::ConcreteStop() { return true; } int SimpleProcessing::InControl_cb( TControlData value ) { return 0; } } clam-1.4.0/test/Visualization/TestModelController/Stubs/FakeCompositeControlWidget.hxx0000644000000000000000000000171610610720021027773 0ustar rootroot#ifndef __FAKECOMPOSITECONTROLWIDGET__ #define __FAKECOMPOSITECONTROLWIDGET__ #include #include "FakeControlWidget.hxx" #include namespace CLAMVM { class ProcessingInControlSet; } namespace CLAMDraft { using CLAMVM::ProcessingInControlSet; using CLAMVM::Presentation; class FakeCompositeControlWidget : public Presentation { private: FakeControlWidget mControl1; FakeControlWidget mControl2; FakeControlWidget mControl3; FakeControlWidget mControl4; FakeControlWidget mControl5; FakeControlWidget mControl6; protected: public: FakeCompositeControlWidget( ); ~FakeCompositeControlWidget(); void SendTheseValues( const std::vector& values ); virtual void AttachTo( ProcessingInControlSet& ); virtual void Detach(); virtual void Show(); virtual void Hide(); }; } #endif // FakeCompositeControlWidget.hxx clam-1.4.0/test/Visualization/TestModelController/Stubs/FakeControlWidget.cxx0000644000000000000000000000136510610720021026103 0ustar rootroot#include "FakeControlWidget.hxx" #include "InputControlModel.hxx" #include namespace CLAMDraft { using CLAMVM::InputControlModel; FakeControlWidget::FakeControlWidget() { ReceiveValue.Wrap( this, &FakeControlWidget::OnNewValue ); } FakeControlWidget::~FakeControlWidget() { } void FakeControlWidget::OnNewValue( TData value ) { std::cout << "Model value: " << value << std::endl; } void FakeControlWidget::AttachTo( InputControlModel& model ) { model.ValuePublished.Connect( ReceiveValue ); SendValue.Connect( model.UpdateValue ); } void FakeControlWidget::Detach() { ReceiveValue.Unbind(); } void FakeControlWidget::Show() { } void FakeControlWidget::Hide() { } } clam-1.4.0/test/Visualization/TestModelController/Stubs/FakeControlWidget.hxx0000644000000000000000000000146010610720021026104 0ustar rootroot#ifndef __FAKECONTROLWIDGET__ #define __FAKECONTROLWIDGET__ #include #include #include #include namespace CLAMVM { class InputControlModel; } namespace CLAMDraft { using CLAMVM::Presentation; using SigSlot::Slotv1; using SigSlot::Signalv1; using CLAM::TData; using CLAMVM::InputControlModel; class FakeControlWidget : public Presentation { protected: virtual void OnNewValue( TData value ); public: virtual void AttachTo( InputControlModel& ); virtual void Detach(); virtual void Show(); virtual void Hide(); FakeControlWidget(); ~FakeControlWidget(); Slotv1 ReceiveValue; Signalv1 SendValue; }; } #endif // FakeControlWidget.hxx clam-1.4.0/test/Visualization/TestModelController/Stubs/SimpleProcessing.hxx0000644000000000000000000000216311324114460026027 0ustar rootroot#ifndef __SIMPLEPROCESSING__ #define __SIMPLEPROCESSING__ #include namespace CLAM { namespace Test { class SimpleProcessingConfig : public ProcessingConfig { DYNAMIC_TYPE_USING_INTERFACE( SimpleProcessingConfig, 1, ProcessingConfig ); DYN_ATTRIBUTE( 0, public, std::string, Name ); protected: void DefaultInit(); }; class SimpleProcessing : public Processing { public: SimpleProcessing(); SimpleProcessing( const SimpleProcessingConfig& cfg ); ~SimpleProcessing(); virtual bool Do(); inline const ProcessingConfig& GetConfig() const { return mConfig; } virtual const char* GetClassName() const { return "CLAMDraft::SimpleProcessing"; } FloatInControl& GetControl() { return mInControl; } protected: bool ConcreteConfigure( const ProcessingConfig& cfg ); bool ConcreteStart(); bool ConcreteStop(); int InControl_cb( TControlData value ); private: SimpleProcessingConfig mConfig; FloatInControl mInControl; }; } } #endif // SimpleProcessing.hxx clam-1.4.0/test/Visualization/TestModelController/Stubs/ProcFeatSeveralControls.cxx0000644000000000000000000000656610610720021027311 0ustar rootroot#include "ProcFeatSeveralControls.hxx" namespace CLAMDraft { void ProcFeatSeveralControlsConfig::DefaultInit() { AddAll(); UpdateData(); } ProcFeatSeveralControls::ProcFeatSeveralControls() : mInCtl_0("Control#1", this, &ProcFeatSeveralControls::InCtl0_cb ), mInCtl_1("Control#2", this, &ProcFeatSeveralControls::InCtl1_cb ), mInCtl_2("Control#3", this, &ProcFeatSeveralControls::InCtl2_cb ), mInCtl_3("Control#4", this, &ProcFeatSeveralControls::InCtl3_cb ), mInCtl_4("Control#5", this, &ProcFeatSeveralControls::InCtl4_cb ), mInCtl_5("Control#6", this, &ProcFeatSeveralControls::InCtl5_cb ), mTimesCalled0( 0 ), mTimesCalled1( 0 ), mTimesCalled2( 0 ), mTimesCalled3( 0 ), mTimesCalled4( 0 ), mTimesCalled5( 0 ) { } ProcFeatSeveralControls::ProcFeatSeveralControls( const ProcFeatSeveralControlsConfig& cfg ) : mInCtl_0("Control#1", this, &ProcFeatSeveralControls::InCtl0_cb ), mInCtl_1("Control#2", this, &ProcFeatSeveralControls::InCtl1_cb ), mInCtl_2("Control#3", this, &ProcFeatSeveralControls::InCtl2_cb ), mInCtl_3("Control#4", this, &ProcFeatSeveralControls::InCtl3_cb ), mInCtl_4("Control#5", this, &ProcFeatSeveralControls::InCtl4_cb ), mInCtl_5("Control#6", this, &ProcFeatSeveralControls::InCtl5_cb ), mTimesCalled0( 0 ), mTimesCalled1( 0 ), mTimesCalled2( 0 ), mTimesCalled3( 0 ), mTimesCalled4( 0 ), mTimesCalled5( 0 ) { Configure( cfg ); } ProcFeatSeveralControls::~ProcFeatSeveralControls() { } bool ProcFeatSeveralControls::Do() { return true; } bool ProcFeatSeveralControls::ConcreteConfigure( const ProcessingConfig& cfg ) { CopyAsConcreteConfig( mConfig, cfg ); return true; } bool ProcFeatSeveralControls::ConcreteStart() { mInCtl_0.DoControl( 0 ); mInCtl_1.DoControl( 0 ); mInCtl_2.DoControl( 0 ); mInCtl_3.DoControl( 0 ); mInCtl_4.DoControl( 0 ); mInCtl_5.DoControl( 0 ); return true; } bool ProcFeatSeveralControls::ConcreteStop() { return true; } int ProcFeatSeveralControls::GetControlTimesCalled( int id ) { if ( id == 0 ) return mTimesCalled0; if ( id == 1 ) return mTimesCalled1; if ( id == 2 ) return mTimesCalled2; if ( id == 3 ) return mTimesCalled3; if ( id == 4 ) return mTimesCalled4; if ( id == 5 ) return mTimesCalled5; return 0; } float ProcFeatSeveralControls::GetControlLastValue( int id ) { if ( id == 0 ) return mInCtl_0.GetLastValue(); if ( id == 1 ) return mInCtl_1.GetLastValue(); if ( id == 2 ) return mInCtl_2.GetLastValue(); if ( id == 3 ) return mInCtl_3.GetLastValue(); if ( id == 4 ) return mInCtl_4.GetLastValue(); if ( id == 5 ) return mInCtl_5.GetLastValue(); return -1.0f; } int ProcFeatSeveralControls::InCtl0_cb( TControlData value ) { mTimesCalled0++; return 0; } int ProcFeatSeveralControls::InCtl1_cb( TControlData value ) { mTimesCalled1++; return 0; } int ProcFeatSeveralControls::InCtl2_cb( TControlData value ) { mTimesCalled2++; return 0; } int ProcFeatSeveralControls::InCtl3_cb( TControlData value ) { mTimesCalled3++; return 0; } int ProcFeatSeveralControls::InCtl4_cb( TControlData value ) { mTimesCalled4++; return 0; } int ProcFeatSeveralControls::InCtl5_cb( TControlData value ) { mTimesCalled5++; return 0; } } clam-1.4.0/test/Visualization/TestModelController/Stubs/FakeCompositeControlWidget.cxx0000644000000000000000000000251410610720021027763 0ustar rootroot#include "FakeCompositeControlWidget.hxx" #include "ProcessingInControlSet.hxx" namespace CLAMDraft { using CLAMVM::ProcessingInControlSet; FakeCompositeControlWidget::FakeCompositeControlWidget() { } FakeCompositeControlWidget::~FakeCompositeControlWidget() { } void FakeCompositeControlWidget::AttachTo( ProcessingInControlSet& set ) { mControl1.AttachTo( set.Retrieve( "Control#1" ) ); mControl2.AttachTo( set.Retrieve( "Control#2" ) ); mControl3.AttachTo( set.Retrieve( "Control#3" ) ); mControl4.AttachTo( set.Retrieve( "Control#4" ) ); mControl5.AttachTo( set.Retrieve( "Control#5" ) ); mControl6.AttachTo( set.Retrieve( "Control#6" ) ); } void FakeCompositeControlWidget::Detach() { mControl1.Detach(); mControl2.Detach(); mControl3.Detach(); mControl4.Detach(); mControl5.Detach(); mControl6.Detach(); } void FakeCompositeControlWidget::SendTheseValues( const std::vector& values ) { mControl1.SendValue.Emit( values[0] ); mControl2.SendValue.Emit( values[1] ); mControl3.SendValue.Emit( values[2] ); mControl4.SendValue.Emit( values[3] ); mControl5.SendValue.Emit( values[4] ); mControl6.SendValue.Emit( values[5] ); } void FakeCompositeControlWidget::Show() { } void FakeCompositeControlWidget::Hide() { } } clam-1.4.0/test/Visualization/TestModelController/Stubs/ProcFeatSeveralControls.hxx0000644000000000000000000000346211324114460027315 0ustar rootroot#ifndef __PROCFEATSEVERALCONTROLS__ #define __PROCFEATSEVERALCONTROLS__ #include namespace CLAM { namespace Test { using CLAM::Processing; using CLAM::ProcessingConfig; using CLAM::TControlData; class ProcFeatSeveralControlsConfig : public ProcessingConfig { DYNAMIC_TYPE_USING_INTERFACE( ProcFeatSeveralControlsConfig, 1, ProcessingConfig ); DYN_ATTRIBUTE( 0, public, std::string, Name ); protected: void DefaultInit(); }; class ProcFeatSeveralControls : public Processing { public: ProcFeatSeveralControls(); ProcFeatSeveralControls( const ProcFeatSeveralControlsConfig& cfg ); ~ProcFeatSeveralControls(); virtual bool Do(); inline const ProcessingConfig& GetConfig() const { return mConfig; } virtual const char* GetClassName() const { return "CLAMDraft::ProcFeatSeveralControls"; } int GetControlTimesCalled( int id ); float GetControlLastValue( int id ); protected: bool ConcreteConfigure( const ProcessingConfig& cfg ); bool ConcreteStart(); bool ConcreteStop(); int InCtl0_cb( TControlData value ); int InCtl1_cb( TControlData value ); int InCtl2_cb( TControlData value ); int InCtl3_cb( TControlData value ); int InCtl4_cb( TControlData value ); int InCtl5_cb( TControlData value ); private: ProcFeatSeveralControlsConfig mConfig; FloatInControl mInCtl_0; FloatInControl mInCtl_1; FloatInControl mInCtl_2; FloatInControl mInCtl_3; FloatInControl mInCtl_4; FloatInControl mInCtl_5; int mTimesCalled0; int mTimesCalled1; int mTimesCalled2; int mTimesCalled3; int mTimesCalled4; int mTimesCalled5; }; } } #endif // ProcFeatSeveralControls.hxx clam-1.4.0/test/Visualization/test_singleplot.cxx0000644000000000000000000000255507737263724020741 0ustar rootroot#include "Plot.hxx" #include "SystemPlots.hxx" #include "DataTypes.hxx" #include "Array.hxx" #include "BPF.hxx" #include void buildTestArray( CLAM::Array& array ) { array.Resize( 100 ); array.SetSize( 100 ); for ( int i = 0; i < 100; i++ ) { array[i] = float(i)*0.005; } } void buildTestBPF( CLAM::BPF& bpf ) { bpf.Insert( -10.0, 0.0 ); bpf.Insert( -5.0, 0.45 ); bpf.Insert( 0.0, 1.0 ); bpf.Insert( 5.0, 0.75 ); bpf.Insert( 10.0, 0.0 ); } int main( int argc, char** argv ) { CLAM::Array population; CLAM::BPF func; CLAMVM::Plot myUglyPlot( "igloo" ); myUglyPlot.SetPosition( 100, 100 ); myUglyPlot.SetSize( 640, 480 ); myUglyPlot.SetLabel( "My ugly plot" ); myUglyPlot.SetYRange( 0.0, 1.0 ); myUglyPlot.SetColor( CLAMVM::Color( 150, 150, 0 ) ); CLAMVM::Plot myUglyPlot2( "igloo2" ); myUglyPlot2.SetPosition( 100, 100 ); myUglyPlot2.SetSize( 640, 480 ); myUglyPlot2.SetLabel( "My ugly plot" ); myUglyPlot2.SetYRange( 0.0, 1.0 ); myUglyPlot2.SetTooltipFormat( "x=%3.2f, P(x)=%1.3f" ); myUglyPlot2.SetColor( CLAMVM::Color( 0, 150, 150 ) ); buildTestArray( population ); myUglyPlot.SetData( population, 0, 99 ); //CLAMVM::SystemPlots::Display( "igloo" ); buildTestBPF( func ); myUglyPlot2.SetData( func ); //CLAMVM::SystemPlots::Display( "igloo2" ); CLAMVM::SystemPlots::Display( "igloo" ); return 0; } clam-1.4.0/test/Visualization/test_SpecificPlots.cxx0000644000000000000000000000722710610720021021275 0ustar rootroot#include "AudioPlot.hxx" #include "SpectrumPlot.hxx" #include "SinTracksPlot.hxx" #include "SpectrumAndPeaksPlot.hxx" #include "SystemPlots.hxx" #include "FundFreqPlot.hxx" #include "Segment.hxx" #include "XMLStorage.hxx" #include "AudioFileIn.hxx" // this header imports the CLAM::AudioFileIn Processing class interface #include #include "Err.hxx" #include #include #include void loadWAVEFile( const std::string& filename, CLAM::Audio& object ) { CLAM::AudioFileIn fileLoader; CLAM::AudioFileConfig fileLoaderConfig; fileLoaderConfig.SetFilename( filename ); fileLoaderConfig.SetFiletype( CLAM::EAudioFileType::eWave ); if ( !fileLoader.Configure( fileLoaderConfig ) ) { std::cerr << "ERROR: could not open " << filename << std::endl; exit(-1); } CLAM::TSize nSamples = fileLoader.Size(); CLAM::TData sampleRate = fileLoader.SampleRate(); object.SetSize( nSamples ); object.SetSampleRate( sampleRate ); fileLoader.Start(); fileLoader.Do( object ); fileLoader.Stop(); } void loadSegment( const std::string& filename, CLAM::Segment& object ) { CLAM::XMLStorage x; x.Restore( object, filename ); } int main( int argc, char** argv ) { try { // Data objects CLAM::Segment theData; CLAM::Audio theWAVEFile; // Plots CLAMVM::AudioPlot theAudioPlot; theAudioPlot.SetLabel( "An audio signal" ); theAudioPlot.SetSize( 640, 480 ); CLAMVM::SpectrumPlot theSpectrumPlot; theSpectrumPlot.SetLabel( "An spectrum" ); theSpectrumPlot.SetSize( 640, 480 ); CLAMVM::SpectrumAndPeaksPlot theSpecAndPeaksPlot; theSpecAndPeaksPlot.SetLabel( "An spectrum and detected peaks" ); theSpecAndPeaksPlot.SetSize( 640, 480 ); CLAMVM::SinTracksPlot theSinTracksPlot; theSinTracksPlot.SetLabel( "Sinusoidal tracks in a segment" ); theSinTracksPlot.SetSize( 640, 480 ); CLAMVM::FundFreqPlot theFundFreqPlot; theFundFreqPlot.SetLabel( "Fundamental frequency in a segment" ); theFundFreqPlot.SetSize( 640, 480 ); // filenames std::string selectedWaveFile; std::string selectedXMLFile; const char* tmp = NULL; tmp = fl_file_chooser( "Select the WAVE file to load", "*.wav", NULL, 1 ); if ( tmp ) selectedWaveFile = tmp; tmp = fl_file_chooser( "Select the SMS Tools XML analysis file to load", "*.xml", NULL, 1 ); if ( tmp ) selectedXMLFile = tmp; std::cout << "Loading WAVE file... " ; std::cout.flush(); loadWAVEFile( selectedWaveFile, theWAVEFile ); std::cout << "DONE!" << std::endl; std::cout << "Loading Segment... "; std::cout.flush(); loadSegment( selectedXMLFile, theData ); std::cout << "DONE!" << std::endl; // plots data setting theAudioPlot.SetData( theWAVEFile ); CLAM::Spectrum& anSpectrumInTheMiddle = theData.GetFrame( theData.GetnFrames() / 2 ).GetResidualSpec(); theSpectrumPlot.SetData( anSpectrumInTheMiddle ); CLAM::Spectrum& anotherSpectrumInTheMiddle = theData.GetFrame( theData.GetnFrames() / 2).GetSinusoidalAnalSpectrum(); CLAM::SpectralPeakArray& attachedPeakArray = theData.GetFrame( theData.GetnFrames() / 2).GetSpectralPeakArray(); theSpecAndPeaksPlot.SetData( anotherSpectrumInTheMiddle, attachedPeakArray ); theSinTracksPlot.SetData( theData ); theFundFreqPlot.SetData( theData ); CLAMVM::SystemPlots::DisplayAll(); } catch( CLAM::Err& e ) { std::cerr << "A CLAM error occurred!" << std::endl; e.Print(); exit(-1); } catch( std::exception& e ) { std::cerr << e.what() << std::endl; exit( -1 ); } catch( ... ) { std::cerr << "Unknown exception caught" << std::endl; exit( -1 ); } return 0; } clam-1.4.0/test/Visualization/test_multiplot.cxx0000644000000000000000000000224307737263724020604 0ustar rootroot#include "MultiPlot.hxx" #include "SystemPlots.hxx" #include "DataTypes.hxx" #include "Array.hxx" #include "BPF.hxx" #include void buildTestArray( CLAM::Array& array ) { array.Resize( 100 ); array.SetSize( 100 ); for ( int i = 0; i < 100; i++ ) { array[i] = float(i)*0.005; } } void buildTestBPF( CLAM::BPF& bpf ) { bpf.Insert( -10.0, 0.0 ); bpf.Insert( -5.0, 0.45 ); bpf.Insert( 0.0, 1.0 ); bpf.Insert( 5.0, 0.75 ); bpf.Insert( 10.0, 0.0 ); } int main( int argc, char** argv ) { CLAM::Array population; CLAM::BPF func; buildTestArray( population ); buildTestBPF( func ); CLAMVM::MultiPlot myUglyPlot( "igloo" ); myUglyPlot.SetPosition( 100, 100 ); myUglyPlot.SetSize( 640, 480 ); myUglyPlot.SetLabel( "My ugly plot" ); myUglyPlot.SetYRange( 0.0, 1.0 ); myUglyPlot.SetTooltipFormat( "x=%3.2f, P(x)=%1.3f" ); myUglyPlot.SetColor( "Empirical PDF", CLAMVM::Color( 150, 150, 0 ) ); myUglyPlot.AddData( "Empirical PDF", population, 0, 99 ); myUglyPlot.SetColor( "Theoretical PDF", CLAMVM::Color( 0, 150, 150 ) ); myUglyPlot.AddData( "Theoretical PDF", func ); CLAMVM::SystemPlots::Display( "igloo" ); return 0; } clam-1.4.0/test/Visualization/TestFl_SpectrumPeaks.cxx0000644000000000000000000000475610610720021021542 0ustar rootroot#include "Frame.hxx" #include "Spectrum.hxx" #include "SpectralPeakArray.hxx" #include "LogMagSpectrumAdapter.hxx" #include "SpectralPeakArrayAdapter.hxx" #include "Fl_SpectrumPeaks.hxx" #include "XMLStorage.hxx" #include "Err.hxx" #include "WidgetTKWrapper.hxx" #include #include #include using CLAM::SpectralPeakArray; using CLAM::Spectrum; using CLAM::Frame; using CLAM::XMLStorage; using CLAMVM::LogMagSpectrumAdapter; using CLAMVM::SpectralPeakArrayAdapter; using CLAMVM::Fl_SpectrumPeaks; using CLAMVM::WidgetTKWrapper; static const char* sPathToData="./Datasets/"; bool TestBasicUseCase( LogMagSpectrumAdapter& specView, SpectralPeakArrayAdapter& peaksView, Fl_SpectrumPeaks& peaksWidget ) { XMLStorage x; Spectrum spec; SpectralPeakArray peaks; std::string filename1 = "ResidualSpectrum.xml"; std::string pathToFile1 = sPathToData; pathToFile1+=filename1; std::string filename2 = "SpectralPeakArray.xml"; std::string pathToFile2 = sPathToData; pathToFile2+=filename2; x.Restore( peaks, pathToFile2 ); x.Restore( spec, pathToFile1 ); // The frame has been incorporated into the system specView.BindTo( spec ); peaksView.BindTo( peaks ); specView.Publish(); peaksView.Publish(); peaksWidget.Show(); WidgetTKWrapper& tk = WidgetTKWrapper::GetWrapperFor("FLTK"); tk.Run(); return true; } int main( int argc, char** argv ) { try { LogMagSpectrumAdapter spectrumView; SpectralPeakArrayAdapter peaksView; Fl_SpectrumPeaks presentation( 100, 100, 640, 480, "Spectrum + peaks" ); presentation.AttachTo( spectrumView, peaksView ); std::cerr << "BASIC SPECTRAL PEAK ARRAY USE CASE TEST LAUNCHED" << std::endl; if ( !TestBasicUseCase( spectrumView, peaksView, presentation ) ) std::cerr << "Basic Use case Test...... FAILED!" << std::endl; else std::cerr << "Basic Use case Test...... Passed!" << std::endl; } catch ( CLAM::Err& e ) { std::cerr << "A CLAM controlled error has occured" << std::endl; e.Print(); std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( std::exception& e ) { std::cerr << "An standard library error has occured" << std::endl; std::cerr << e.what() << std::endl; std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( ... ) { std::cerr << "An unknown error has occured!" << std::endl; return -1; } return 0; } clam-1.4.0/test/Visualization/TestSinTracksView.cxx0000644000000000000000000000345210610720021021057 0ustar rootroot#include "Segment.hxx" #include "SinTracksAdapter.hxx" #include "StdioSinTracksPresentation.hxx" #include "XMLStorage.hxx" #include "Err.hxx" #include #include #include using CLAM::Segment; using CLAM::XMLStorage; using CLAMVM::SinTracksAdapter; using CLAMVM::StdioSinTracksPresentation; static const char* sPathToData = "./Datasets/"; bool TestBasicUseCase( SinTracksAdapter& view, StdioSinTracksPresentation& presentation ) { XMLStorage x; Segment segmentObj; std::string filename = "Segment.xml"; std::string pathToFile = sPathToData; pathToFile+=filename; x.Restore( segmentObj, pathToFile ); std::cout << "SEGMENT RESTORED" << std::endl; view.BindTo( segmentObj ); view.Publish(); std::cout << "DATA ACQUISITION DONE!" << std::endl; presentation.Show(); return true; } int main( int argc, char** argv ) { try { SinTracksAdapter view; StdioSinTracksPresentation presentation; presentation.AttachTo( view ); std::cerr << "BASIC SPECTRAL PEAK ARRAY USE CASE TEST LAUNCHED" << std::endl; if ( !TestBasicUseCase( view, presentation ) ) std::cerr << "Basic Use case Test...... FAILED!" << std::endl; else std::cerr << "Basic Use case Test...... Passed!" << std::endl; } catch ( CLAM::Err& e ) { std::cerr << "A CLAM controlled error has occured" << std::endl; e.Print(); std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( std::exception& e ) { std::cerr << "An standard library error has occured" << std::endl; std::cerr << e.what() << std::endl; std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( ... ) { std::cerr << "An unknown error has occured!" << std::endl; return -1; } return 0; } clam-1.4.0/test/Visualization/WindowedSpectrumGenerator.hxx0000644000000000000000000000340310610720021022636 0ustar rootroot#ifndef __WINDOWEDSPECTRUMGENERATOR__ #define __WINDOWEDSPECTRUMGENERATOR__ #include "ProcessingComposite.hxx" #include "AudioMultiplier.hxx" #include "WindowGenerator.hxx" #include "FFT_rfftw.hxx" #include "Audio.hxx" using namespace CLAM; namespace CLAMTest { class WindowedSpectrumGeneratorConfig : public ProcessingConfig { public: DYNAMIC_TYPE_USING_INTERFACE( WindowedSpectrumGeneratorConfig, 4, ProcessingConfig ); DYN_ATTRIBUTE( 0, public, std::string, Name ); DYN_ATTRIBUTE( 1, public, EWindowType, WindowType ); DYN_ATTRIBUTE( 2, public, TData, SampleRate ); DYN_ATTRIBUTE( 3, public, TSize, FrameSize ); void DefaultInit(); }; class WindowedSpectrumGenerator : public ProcessingComposite { public: WindowedSpectrumGenerator(); WindowedSpectrumGenerator( const WindowedSpectrumGeneratorConfig& cfg ); ~WindowedSpectrumGenerator() { } virtual bool Do(); virtual bool Do( Audio& inAudio, Spectrum& outSpectra ); void SetWindowingType( EWindowType wtype ); void SetLogOutput( ) { mConvertToLog = true; } void SetLinearOutput( ) { mConvertToLog = false; } inline const ProcessingConfig& GetConfig() const { return mConfig; } virtual const char *GetClassName() const { return "WindowedSpectrumGenerator"; } protected: virtual bool ConcreteConfigure( const ProcessingConfig& cfg ); virtual bool ConcreteStart(); virtual bool ConcreteStop(); private: WindowedSpectrumGeneratorConfig mConfig; // PO's WindowGenerator mWindowGen; AudioMultiplier mWindowApplier; FFT_rfftw mAnalysis; Audio mWindowedAudio; Audio mWindow; bool mConvertToLog; }; } #endif // WindowedSpectrumGenerator.hxx clam-1.4.0/test/Visualization/StdioAudioPresentation.hxx0000644000000000000000000000231710610720021022127 0ustar rootroot#ifndef __STDIOAUDIOPRESENTATION__ #define __STDIOAUDIOPRESENTATION__ #include "Presentation.hxx" #include "Array.hxx" #include "DataTypes.hxx" #include "Slotv1.hxx" namespace CLAMVM { using SigSlot::Slotv1; using CLAM::DataArray; using CLAM::TData; using CLAM::TTime; class AudioModel; class StdioAudioPresentation : public Presentation { // attributes private: TData mMaximum; TData mMinimum; TTime mAudioLen; TTime mAudioStart; TData mSampleRate; // Implementation details protected: // callback methods to retrieving data from the vie //public slots: virtual void OnNewSamples( const DataArray& array ); virtual void OnNewDuration( TTime secs ); virtual void OnNewStartTime( TTime secs ); virtual void OnNewSampleRate( TData rate ); // Public class interface public: StdioAudioPresentation(); // slots Slotv1 SetSamples; Slotv1 SetDuration; Slotv1 SetStartTime; Slotv1 SetSampleRate; virtual ~StdioAudioPresentation(); void Show(); void Hide(); virtual void AttachTo( AudioModel& ); void Detach(); }; } #endif // StdioAudioPresentation.hxx clam-1.4.0/test/Visualization/StdioSinTracksPresentation.cxx0000644000000000000000000000455310610720021022766 0ustar rootroot#include "StdioSinTracksPresentation.hxx" #include "SinTracksModel.hxx" //#include "SinTrackSegment.hxx" #include #include namespace CLAMVM { void StdioSinTracksPresentation::dump_to_stdout::operator()( const SinusoidalTrack& st ) { if ( st.empty() ) { std::cout << "(WW) Track #" << real_track_id << " was empty!" << std::endl; return; } SinusoidalTrack::const_iterator i, end; i = st.begin(); end = st.end(); std::cout << "Track #" << real_track_id << std::endl; while ( i != end ) { if ( i->isValid() ) { std::cout << "(" << i->mFreq << "," << i->mTimeIndex << "," << i->mMag << ") "; } i++; } std::cout << " " << std::endl; real_track_id++; } StdioSinTracksPresentation::StdioSinTracksPresentation() : mSineTracks( NULL ) { SetPartials.Wrap( this, &StdioSinTracksPresentation::OnNewTrackList ); SetSpectralRange.Wrap( this, &StdioSinTracksPresentation::OnNewRange ); SetDuration.Wrap( this, &StdioSinTracksPresentation::OnNewDuration ); } StdioSinTracksPresentation::~StdioSinTracksPresentation() { } void StdioSinTracksPresentation::AttachTo( SinTracksModel& model ) { model.TrackListPublished.Connect( SetPartials ); model.SpectralRangePublished.Connect( SetSpectralRange ); model.DurationPublished.Connect( SetDuration ); } void StdioSinTracksPresentation::Detach() { SetPartials.Unbind(); SetSpectralRange.Unbind(); SetDuration.Unbind(); } void StdioSinTracksPresentation::Show() { // we will dump the present tracks as well as the valid segments present in each track decimate_sine_tracks Decimate( 3 ); std::cout << "DECIMATION... "; Decimate( *mSineTracks ); std::cout << "DONE!" << std::endl; std::for_each( mSineTracks->begin(), mSineTracks->end(), dump_to_stdout() ); } void StdioSinTracksPresentation::Hide() { } void StdioSinTracksPresentation::OnNewRange( TData spec_rng ) { mSpectralRange = spec_rng; } void StdioSinTracksPresentation::OnNewDuration( TTime begin, TTime end ) { mBeginTime = begin; mEndTime = end; mLen = end - begin; } void StdioSinTracksPresentation::OnNewTrackList( SineTrackList& list, TSize framelen ) { // ufff mSineTracks = &list; } } clam-1.4.0/test/Visualization/TestFl_SinTracks.cxx0000644000000000000000000000414210610720021020642 0ustar rootroot#include "Segment.hxx" #include "SinTracksAdapter.hxx" #include "Fl_SinTracks.hxx" #include "WidgetTKWrapper.hxx" #include "XMLStorage.hxx" #include "Err.hxx" #include #include #include #include using CLAM::Segment; using CLAM::XMLStorage; using CLAMVM::SinTracksAdapter; using CLAMVM::Fl_SinTracks; using CLAMVM::WidgetTKWrapper; static const char* sPathToData = "./Datasets/"; static const char* sFilename = 0; bool TestBasicUseCase( SinTracksAdapter& view, Fl_SinTracks& presentation ) { XMLStorage x; Segment segmentObj; /* std::string filename = "Segment.xml"; std::string pathToFile = sPathToData; pathToFile+=filename; */ x.Restore( segmentObj, sFilename ); std::cout << "SEGMENT RESTORED" << std::endl; view.BindTo( segmentObj ); view.Publish(); std::cout << "DATA ACQUISITION DONE!" << std::endl; presentation.Show(); WidgetTKWrapper& tk = WidgetTKWrapper::GetWrapperFor("FLTK"); tk.Run(); return true; } int main( int argc, char** argv ) { try { sFilename = fl_file_chooser( "Please, select analysis data", "*.xml", NULL ); if ( sFilename == NULL ) { std::cout << "Quitting!" << std::endl; exit(0); } SinTracksAdapter view; Fl_SinTracks presentation(100,100,640,480, "Some sinusoidal tracks..."); presentation.AttachTo( view ); std::cerr << "BASIC SPECTRAL PEAK ARRAY USE CASE TEST LAUNCHED" << std::endl; if ( !TestBasicUseCase( view, presentation ) ) std::cerr << "Basic Use case Test...... FAILED!" << std::endl; else std::cerr << "Basic Use case Test...... Passed!" << std::endl; } catch ( CLAM::Err& e ) { std::cerr << "A CLAM controlled error has occured" << std::endl; e.Print(); std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( std::exception& e ) { std::cerr << "An standard library error has occured" << std::endl; std::cerr << e.what() << std::endl; std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( ... ) { std::cerr << "An unknown error has occured!" << std::endl; return -1; } return 0; } clam-1.4.0/test/Visualization/DummyTDWidget.cxx0000644000000000000000000000122110610720021020142 0ustar rootroot#include "DummyTDWidget.hxx" #include namespace CLAMVM { DummyTDWidget::DummyTDWidget() { } DummyTDWidget::~DummyTDWidget() { } void DummyTDWidget::EmitValue( TControlData value ) { SendValue.Emit( value ); } void DummyTDWidget::Show() { } void DummyTDWidget::Hide() { } void DummyTDWidget::OnNewValue( TControlData value ) { std::cout << "New value received: " << value << std::endl; } void DummyTDWidget::OnNewRange( TControlData min, TControlData max ) { std::cout << "New range received: " << std::endl; std::cout << "\t + min: " << min << std::endl; std::cout << "\t + max: " << max << std::endl; } } clam-1.4.0/test/Visualization/TestTokenDelayController.cxx0000644000000000000000000000505010610720021022422 0ustar rootroot#include "Err.hxx" #include "TokenDelay.hxx" #include "Spectrum.hxx" #include "TokenDelayController.hxx" #include "DummyTDWidget.hxx" #include "Assert.hxx" #include using CLAM::Err; using CLAM::TokenDelay; using CLAM::TokenDelayConfig; using CLAM::Spectrum; using CLAMVM::SpectralTokenDelayController; using CLAMVM::DummyTDWidget; // Just check that binding and attaching are working right void TestBasicUse() { TokenDelayConfig cfg; cfg.SetMaxDelay( 3 ); SpectralTokenDelayController controller; TokenDelay specDelay; DummyTDWidget widget; specDelay.Configure( cfg ); specDelay.Start(); controller.BindTo( specDelay ); widget.AttachTo( controller.Retrieve("Delay Control") ); controller.Publish(); specDelay.Stop(); } void TestUseCase_ValueSending() { TokenDelayConfig cfg; cfg.SetMaxDelay( 3 ); SpectralTokenDelayController controller; TokenDelay specDelay; DummyTDWidget widget; specDelay.Configure( cfg ); specDelay.Start(); controller.BindTo( specDelay ); widget.AttachTo( controller.Retrieve("Delay Control") ); // required to synchronize the Controller and the Widget controller.Publish(); // Some value sending widget.EmitValue( 1 ); controller.Update(); CLAM_ASSERT( specDelay.GivenDelay() == 1 , "Test Use Case: Value Sending FAILED - the token delay object did not receive the value" ); widget.EmitValue( 2 ); controller.Update(); CLAM_ASSERT( specDelay.GivenDelay() == 2 , "Test Use Case: Value Sending FAILED - the token delay object did not receive the value" ); widget.EmitValue( 5 ); controller.Update(); CLAM_ASSERT( specDelay.GivenDelay() == 2 , "Test Use Case: Value Sending FAILED - the ControlAdapter did not clamp the control value to the valid range" ); specDelay.Stop(); } int main( int argc, char** argv ) { std::cout << "TestTokenDelayController PASSED!" << std::endl; try { TestBasicUse(); std::cout << "Basic Use Case test PASSED!" << std::endl; TestUseCase_ValueSending(); std::cout << "Use Case test: Value Sending PASSED!" << std::endl; } catch ( CLAM::Err& e ) { std::cerr << "A CLAM controlled error has occured" << std::endl; e.Print(); std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( std::exception& e ) { std::cerr << "An standard library error has occured" << std::endl; std::cerr << e.what() << std::endl; std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( ... ) { std::cerr << "An unknown error has occured!" << std::endl; return -1; } return 0; } clam-1.4.0/test/Visualization/Test_FlEnvelope.cxx0000644000000000000000000000336010610720021020517 0ustar rootroot#include #include #include #include #include "Fl_Envelope_Scroll.H" #include "CLAM_Math.hxx" #include void dragcb(Fl_Envelope_Scroll* e,Fl_Output* o) { unsigned dragged = e->envelope->dragging(); if (dragged > e->envelope->points()) return; FLPOINT& p=e->envelope->point(dragged); char tmp[256]; sprintf(tmp,"%2.2f,%2.2f",p.x,p.y); o->value(tmp); } void writecb(Fl_Button* b,Fl_Envelope* e) { int i=0; FILE* f=fopen("output.txt","w"); const unsigned N = e->points(); for (int i=0; ipoint(i); fclose(f); } void snapcb(Fl_Check_Button* b,Fl_Envelope* e) { if (b->value()) e->snap(SNAPBOTH); else e->snap(0); } int main( int argc, char** argv ) { Fl_Window w(300,300); Fl_Output output(5,5,90,20); Fl_Button write(100,5,90,20,"Write"); Fl_Check_Button snap(200,5,90,20,"Snap"); Fl_Envelope_Scroll s(5,30,265,265); w.end(); w.resizable( s ); //s.control.hvalue(0,1,-1,2); //s.control.hvalue( 0, 1, -1, 2 ); s.control->hvalue( 0, 22050, 0, 22050 ); //s.control.vvalue( 0, 1, -1, 2 ); s.control->vvalue( 0, 150, -150, 150 ); //s.envelope.grid(.1f,.1f); s.envelope->grid( 100, 5 ); s.envelope->snap(0); s.envelope->margin(30,20,0,0); s.margin_adjust(); s.callback((Fl_Callback*) dragcb,&output); write.callback((Fl_Callback*) writecb,&s.envelope); snap.callback((Fl_Callback*) snapcb,&s.envelope); /* for (float f=-1;f<1;f+=0.025f) { s.envelope.add_point(f,sin(f*3.+2.*cos(f*6.))); } */ s.envelope->add_point( 0, -30 ); s.envelope->add_point( 6000, -30 ); s.envelope->add_point( 6500, -60 ); s.envelope->add_point( 8500, -120 ); s.envelope->add_point( 22050, -150 ); w.show(); Fl::run(); return 0; } clam-1.4.0/test/Visualization/WindowedSpectrumGenerator.cxx0000644000000000000000000000527510610720021022642 0ustar rootroot#include "WindowedSpectrumGenerator.hxx" #include "Spectrum.hxx" #include "SpectrumConfig.hxx" #include namespace CLAMTest { void WindowedSpectrumGeneratorConfig::DefaultInit() { AddAll(); UpdateData(); SetName( "unnamedGenerator" ); SetFrameSize(1024); SetWindowType( EWindowType::eBlackmanHarris92 ); SetSampleRate( TData(44100) ); } WindowedSpectrumGenerator::WindowedSpectrumGenerator() : mConvertToLog( false ) { Configure( WindowedSpectrumGeneratorConfig() ); } WindowedSpectrumGenerator::WindowedSpectrumGenerator( const WindowedSpectrumGeneratorConfig& cfg) : mConvertToLog( false ) { Configure( cfg ); } bool WindowedSpectrumGenerator::ConcreteConfigure( const ProcessingConfig& cfg ) { CopyAsConcreteConfig(mConfig,cfg ); mWindowedAudio.SetSize( mConfig.GetFrameSize() ); mWindow.SetSize( mConfig.GetFrameSize() ); // let's configure the children WindowGeneratorConfig wndGenCfg; wndGenCfg.SetType( mConfig.GetWindowType() ); wndGenCfg.SetSize( mConfig.GetFrameSize() ); wndGenCfg.SetNormalize( EWindowNormalize::eAnalysis ); mWindowGen.Configure( wndGenCfg ); FFTConfig fftCfg; fftCfg.SetAudioSize( mConfig.GetFrameSize() ); mAnalysis.Configure( fftCfg ); return true; } bool WindowedSpectrumGenerator::Do() { std::cerr << "WindowedSpectrumGenerator::Do()" << " not implemented yet!" << std::endl; return true; } bool WindowedSpectrumGenerator::Do( Audio& inAudio, Spectrum& outSpectra ) { CLAM_ASSERT( mConfig.GetSampleRate() == inAudio.GetSampleRate(), "Configuration sample rate and input sample rate differ!" ); SpecTypeFlags sflags; sflags.bMagPhase=true; sflags.bComplex=true; SpectrumConfig sConfig; sConfig.SetType( sflags ); sConfig.SetSize( mConfig.GetFrameSize()/2 + 1 ); outSpectra.Configure( sConfig ); outSpectra.SetSpectralRange( mConfig.GetSampleRate()/2 ); mWindow.SetSampleRate( mConfig.GetSampleRate() ); mWindowedAudio.SetSampleRate( mConfig.GetSampleRate() ); mWindowGen.Do( mWindow ); mWindowApplier.Do( inAudio, mWindow, mWindowedAudio ); mAnalysis.Do( mWindowedAudio, outSpectra ); if ( mConvertToLog ) { outSpectra.ToDB(); } return true; } void WindowedSpectrumGenerator::SetWindowingType( EWindowType wtype ) { WindowedSpectrumGeneratorConfig cfg = mConfig; cfg.SetWindowType( wtype ); Stop(); Configure(cfg); } bool WindowedSpectrumGenerator::ConcreteStart() { mWindowGen.Start(); mWindowApplier.Start(); mAnalysis.Start(); return true; } bool WindowedSpectrumGenerator::ConcreteStop() { mWindowGen.Stop(); mWindowApplier.Stop(); mAnalysis.Stop(); return true; } } clam-1.4.0/test/Visualization/TestWav.wav0000644000000000000000000130470707737263724017117 0ustar rootrootRIFF²}WAVEfmt D¬ˆXdataŽ}äÿåÿåÿåÿåÿåÿåÿåÿäÿåÿßÿÚÿÙÿÞÿÙÿ×ÿÕÿØÿÒÿÒÿØÿ×ÿÔÿÔÿØÿØÿÙÿØÿÚÿØÿØÿÚÿÚÿØÿÙÿÚÿÙÿÛÿØÿØÿÖÿÖÿÓÿÑÿÑÿÒÿÐÿÍÿÊÿÉÿÍÿÆÿÆÿÉÿÌÿÉÿÉÿÌÿÏÿÌÿÏÿÌÿÏÿÐÿÈÿÐÿÑÿÏÿÏÿÓÿÔÿÔÿÓÿÓÿÎÿËÿÕÿÔÿÓÿÙÿÕÿÕÿÔÿÔÿ×ÿ×ÿÙÿÙÿÜÿÕÿÐÿÒÿÖÿÙÿÖÿÖÿÚÿÍÿÊÿÍÿÑÿÒÿÑÿÑÿÑÿÐÿÎÿÊÿÊÿÌÿÌÿÎÿÊÿÊÿÊÿÍÿÏÿÍÿÇÿÊÿËÿÅÿÃÿ¾ÿÂÿÅÿÄÿÃÿ½ÿ¼ÿ¾ÿ¿ÿ»ÿ¸ÿ¹ÿ¹ÿ·ÿ·ÿºÿ»ÿºÿ¿ÿ¼ÿ»ÿ·ÿ¶ÿ»ÿ¹ÿ»ÿ¶ÿ»ÿ½ÿ¾ÿ»ÿ»ÿ¾ÿ¾ÿ¸ÿ»ÿ½ÿ¿ÿÂÿÅÿÈÿÊÿÃÿ¼ÿÃÿÉÿÇÿÁÿÄÿÀÿÂÿÁÿÇÿÊÿÊÿÄÿÅÿÉÿÊÿËÿËÿÌÿÎÿÊÿÍÿÎÿÏÿÒÿÌÿÏÿÐÿÏÿÊÿÊÿÆÿÉÿËÿÈÿÌÿËÿËÿËÿËÿËÿÎÿÎÿÉÿÌÿÌÿÎÿÍÿÍÿÎÿÐÿÎÿÊÿÏÿÎÿÍÿÎÿÊÿÎÿÍÿÇÿÌÿÒÿÍÿËÿÍÿÍÿÏÿËÿÎÿÑÿÏÿÍÿÑÿÌÿËÿÊÿÐÿÑÿÏÿÑÿÖÿÒÿÓÿÒÿÓÿÔÿÐÿÖÿÒÿÕÿÔÿÖÿÑÿÌÿÊÿÍÿÎÿËÿÇÿÆÿÅÿÏÿÍÿÌÿÌÿÐÿÌÿÎÿÐÿÏÿÌÿÐÿÒÿÍÿÉÿÍÿÏÿÒÿÒÿÕÿØÿÙÿÖÿÖÿ×ÿÕÿÔÿÒÿÓÿÕÿÐÿÍÿÏÿÐÿÕÿÖÿÍÿÓÿÙÿÖÿÏÿÏÿØÿÛÿØÿÛÿàÿÚÿÕÿÓÿÓÿÔÿÕÿÓÿ×ÿÚÿÙÿÚÿÖÿ×ÿÚÿÝÿÚÿÛÿÛÿÜÿ×ÿÜÿÛÿÜÿÖÿÖÿÛÿÚÿáÿàÿáÿÛÿÛÿÝÿâÿÞÿÛÿßÿáÿßÿÝÿàÿÞÿÜÿÛÿßÿáÿâÿÝÿÛÿÛÿÜÿÙÿÕÿÙÿÜÿáÿßÿÝÿÛÿ×ÿØÿÚÿÜÿÝÿÝÿÜÿÞÿÞÿÙÿØÿØÿØÿÔÿÒÿØÿØÿÛÿÜÿáÿæÿãÿßÿÝÿÚÿÙÿÞÿáÿÞÿâÿâÿàÿÜÿâÿäÿâÿàÿâÿàÿãÿäÿáÿáÿãÿÞÿÞÿÜÿáÿãÿåÿåÿæÿäÿçÿéÿèÿèÿéÿèÿéÿäÿçÿèÿâÿãÿìÿëÿìÿìÿëÿîÿéÿäÿëÿèÿéÿìÿïÿîÿèÿæÿçÿêÿçÿéÿèÿéÿäÿåÿçÿäÿâÿêÿêÿéÿèÿçÿìÿëÿèÿæÿâÿâÿåÿåÿâÿçÿæÿæÿãÿâÿæÿèÿæÿäÿçÿðÿêÿèÿèÿîÿðÿòÿóÿõÿðÿñÿòÿôÿõÿòÿîÿõÿöÿüÿüÿüÿüÿüÿÿÿ            " !!$# !" " !#"&# +-*+0,+111,+%#"&&'')&'),#"" %"$!!""  "!!"''$%#$$ " " ! "!%" &%  " "%" "" !" $&&!%!"'#%%!!"&#''(*-*$#%(#(.,&*"((*$#$+).)&)'*.,+*'+*'(''%*,.,'*((%%%!&%%#"%$!" #&$&)*())('&%+)()')(/3-,00126=?;=:?>5971685348612142643461-,/5531456420233/217/16-377996634783004888:78>>=<6;:97>:<==BHE?:==>?A@B<;9;=>8=>;7?<<@>EGDFFJJHGIJKKFGDDE=?A>BKLEGF@ABGKJLGGEIKHKIKEJKEHDBDGIHGB?<=>?EID?CGHEEHDCCKILQUMLJFEFHIFGGFGJMMLSTWSSSTTUSRQRUSSOOTQKLNPPTQSQLIFCBCBC?<=BAACBACBEEC??=:6432+*'*+.+,+(#&&'##"!  %!"#%$(*%$)" )# !#  !   ûÿýÿùÿöÿúÿùÿ÷ÿùÿûÿûÿýÿùÿþÿùÿøÿ÷ÿüÿûÿýÿöÿôÿòÿ÷ÿúÿ÷ÿöÿôÿõÿþÿûÿùÿþÿýÿøÿüÿüÿøÿüÿüÿÿÿþÿÿÿýÿûÿÿÿûÿþÿþÿÿÿþÿýÿüÿþÿúÿûÿýÿûÿþÿüÿùÿýÿþÿùÿùÿöÿòÿõÿþÿûÿ÷ÿöÿôÿòÿõÿòÿòÿ÷ÿõÿõÿóÿòÿôÿðÿôÿöÿðÿïÿïÿîÿðÿîÿêÿëÿéÿêÿåÿçÿëÿíÿæÿâÿçÿåÿäÿßÿáÿåÿçÿãÿáÿàÿãÿãÿãÿåÿáÿâÿâÿßÿàÿàÿãÿäÿâÿÜÿÛÿÝÿâÿçÿáÿãÿâÿàÿÞÿÜÿÝÿÞÿáÿÞÿÞÿÛÿÚÿÛÿØÿÙÿÚÿÚÿÚÿÛÿÖÿÕÿÙÿÔÿ×ÿÛÿÛÿÒÿÙÿáÿâÿÞÿáÿÜÿÚÿÖÿÔÿÓÿÕÿØÿ×ÿÔÿÔÿÒÿÎÿÏÿ×ÿÐÿÎÿÐÿÐÿÐÿÎÿÎÿÉÿÍÿÊÿÃÿÈÿÇÿÃÿ¿ÿÀÿÁÿ¾ÿ¿ÿÁÿ¿ÿ»ÿºÿºÿ¸ÿ¸ÿµÿµÿ¶ÿºÿ·ÿºÿ¹ÿ¹ÿ»ÿºÿ·ÿµÿ¹ÿ¾ÿ¼ÿ¾ÿÂÿÂÿÄÿÂÿÃÿÉÿÆÿÃÿÁÿÂÿÄÿÄÿÅÿÃÿ¾ÿÀÿ¿ÿºÿ¼ÿ»ÿ¼ÿ¾ÿ·ÿ¶ÿµÿµÿ¼ÿ¹ÿ¸ÿ´ÿ´ÿ®ÿ¯ÿ¬ÿªÿ«ÿ­ÿ¬ÿ²ÿ¬ÿ±ÿ¬ÿ«ÿ«ÿ­ÿ©ÿªÿ«ÿ¨ÿ¥ÿŸÿ ÿ¤ÿ¤ÿ¤ÿ¢ÿžÿ£ÿ¡ÿŸÿ ÿ¢ÿŸÿ¢ÿ¢ÿ ÿ¡ÿŸÿœÿœÿÿšÿšÿ˜ÿ–ÿ–ÿ™ÿ“ÿ–ÿ˜ÿ”ÿŽÿŽÿÿ“ÿ–ÿ—ÿ”ÿ“ÿ”ÿ“ÿšÿ›ÿ”ÿ‘ÿ™ÿ™ÿ•ÿ˜ÿ˜ÿ•ÿ“ÿ–ÿ–ÿ’ÿÿ’ÿ’ÿÿŽÿ”ÿ•ÿ™ÿ“ÿ—ÿ™ÿ“ÿ“ÿ–ÿ—ÿ˜ÿ–ÿ—ÿ•ÿ”ÿšÿ—ÿ—ÿ”ÿÿÿ•ÿ”ÿ‘ÿ‘ÿ“ÿŽÿÿˆÿ†ÿ„ÿ‹ÿ‡ÿ‹ÿ„ÿ‡ÿ‡ÿ„ÿƒÿÿÿÿ}ÿƒÿÿÿÿ}ÿ}ÿ~ÿ€ÿ€ÿ}ÿ~ÿ‚ÿÿÿ€ÿÿ„ÿ|ÿÿÿÿ~ÿƒÿÿƒÿ€ÿ~ÿ„ÿ†ÿ‚ÿ~ÿ~ÿ|ÿ~ÿÿzÿ{ÿ}ÿÿ{ÿzÿ|ÿ|ÿwÿÿ|ÿ~ÿÿÿ}ÿ€ÿ~ÿƒÿ„ÿ‚ÿ~ÿ‚ÿ…ÿƒÿƒÿ„ÿ‚ÿÿÿ~ÿƒÿ„ÿ†ÿ†ÿ†ÿ‚ÿ€ÿ†ÿ†ÿ…ÿ€ÿ…ÿÿ„ÿ„ÿ‚ÿ‚ÿ‚ÿ…ÿ‡ÿ‹ÿŽÿˆÿ…ÿ‡ÿ‡ÿ†ÿ†ÿŠÿ‡ÿ„ÿƒÿƒÿ„ÿÿ}ÿ{ÿzÿxÿzÿ{ÿ{ÿzÿ~ÿÿ|ÿxÿ}ÿ~ÿ€ÿƒÿ{ÿxÿ{ÿ|ÿ{ÿ{ÿ}ÿ}ÿxÿzÿ{ÿ}ÿÿ€ÿ‚ÿ}ÿÿ~ÿzÿ}ÿ|ÿ€ÿ€ÿ}ÿ}ÿ|ÿ{ÿ}ÿ}ÿ{ÿ{ÿzÿ|ÿ€ÿÿzÿ€ÿ~ÿ~ÿzÿ}ÿ€ÿƒÿ‚ÿ~ÿ‚ÿÿ}ÿ~ÿ|ÿÿ{ÿ€ÿÿ€ÿ„ÿ‡ÿˆÿ„ÿ‡ÿÿ~ÿ}ÿ‚ÿ‚ÿÿ€ÿÿ~ÿÿÿ€ÿ{ÿ|ÿyÿ~ÿ€ÿ†ÿƒÿ„ÿ‡ÿŠÿ‹ÿ„ÿ‹ÿˆÿ‰ÿ…ÿÿ‹ÿŠÿ‡ÿŽÿŠÿ†ÿ†ÿŠÿ‡ÿ…ÿˆÿƒÿ†ÿŠÿŠÿ‰ÿ…ÿŠÿ‹ÿ‡ÿ„ÿ‹ÿ’ÿÿÿ‰ÿŒÿÿŠÿ‹ÿ‡ÿ‰ÿ‰ÿ‰ÿ‹ÿ‹ÿÿ’ÿÿÿŒÿŽÿÿ”ÿ’ÿ–ÿœÿÿ˜ÿ‘ÿ‘ÿ’ÿ”ÿ—ÿ—ÿ“ÿ˜ÿ™ÿœÿ ÿœÿœÿ¡ÿŸÿ¥ÿ¬ÿ¤ÿ¡ÿ¢ÿ©ÿ§ÿ¨ÿ«ÿ§ÿ¨ÿ¦ÿ©ÿ¨ÿ§ÿ¡ÿ£ÿ¨ÿ¦ÿ¦ÿ¢ÿ§ÿŸÿ¢ÿ£ÿ¢ÿ¡ÿ¢ÿ¤ÿ©ÿ©ÿªÿ«ÿ±ÿ¯ÿªÿ¬ÿ°ÿ°ÿ°ÿ²ÿ³ÿ°ÿ¯ÿ²ÿ²ÿ²ÿ´ÿ¸ÿ¶ÿ¸ÿ¶ÿ·ÿ´ÿ°ÿµÿµÿ³ÿ²ÿ²ÿ·ÿ´ÿµÿ¹ÿ±ÿ²ÿµÿ·ÿ¸ÿºÿ»ÿ¶ÿºÿºÿ»ÿ½ÿ¹ÿ½ÿ¾ÿÂÿ¾ÿ½ÿÀÿÃÿÅÿÅÿÈÿÌÿÊÿÍÿÓÿÎÿËÿÒÿÎÿÏÿÓÿÔÿØÿÛÿØÿÙÿÙÿÙÿÕÿÔÿØÿÚÿ×ÿÜÿÝÿÝÿÞÿÙÿØÿÚÿÚÿ×ÿØÿ×ÿÜÿÞÿÝÿÙÿÚÿÖÿÖÿÙÿÕÿÖÿÞÿÚÿÔÿØÿÙÿÚÿÖÿÖÿßÿßÿßÿßÿäÿÞÿÞÿÜÿÝÿÞÿáÿâÿâÿâÿäÿãÿåÿæÿäÿâÿÜÿáÿèÿèÿòÿïÿæÿêÿêÿêÿêÿêÿðÿðÿöÿõÿ÷ÿüÿüÿüÿøÿûÿ÷ÿùÿÿÿùÿúÿÿÿþÿüÿýÿ   %()#'((,+)21-3786;>>?>BB>DFE=BECDIRRQVWQSUWZ\[^^]a\\b`decbababddehhjjklllppppnmmpnmpoqminlsqrutrwuuv|{|~|z~ƒ…†‡†ƒ‡„‡Œ„„‡‰‡‰ˆ†Š‰ˆ‡Œ‹ŒˆŠŠŒ‹ƒˆŽŒ‰‹‰Œ‘ŽŽŽŒŒ‘Ž‹ŽŠ‹Š”‘’’”Ž“ŽŒŽ‹‡‡‡ŽŽ‹‹ŽŒŽ‘ŽŒ‰ŠŒŒŒ”’”’”ŽŒŠŽ‡ŽŒ…Šˆ…ˆŽŠŠˆ‰‰’”‘‘Ž“’މ‹Š†ˆ€€‚ƒƒ…†€~||{y{{yuxuxysrpnoqutonnnpqrrppihkiegedebfca_[\]\^_]Z]\[XZSQRRLNPQPONKIJILLOQONNRQQTQSWQLPMCEDGLILHFEEE@??<=DD?9;72484;75-.-./450,//0.-,,&'$(&%(%&('!          ýÿÿÿüÿÿÿþÿÿÿ                             þÿþÿûÿûÿûÿüÿõÿúÿÿÿûÿ÷ÿüÿûÿýÿüÿûÿýÿøÿûÿùÿùÿùÿüÿÿÿýÿùÿûÿõÿðÿôÿøÿùÿÿÿÿÿüÿúÿöÿöÿøÿùÿõÿñÿòÿðÿòÿõÿ÷ÿùÿöÿòÿóÿôÿíÿïÿñÿïÿïÿöÿòÿ÷ÿõÿóÿ÷ÿöÿóÿöÿöÿøÿûÿüÿüÿúÿ÷ÿúÿøÿúÿüÿÿÿýÿüÿüÿÿÿþÿÿÿ  ÿÿþÿ   "!&&#$"  ! ###""$&"$%%*%$))'&$'#%"'$'$$## #!""     ýÿ þÿ ýÿüÿýÿüÿùÿøÿùÿøÿùÿùÿ÷ÿûÿùÿøÿøÿùÿùÿüÿøÿóÿñÿíÿêÿíÿêÿçÿçÿåÿåÿéÿåÿâÿáÿßÿÝÿàÿåÿãÿáÿæÿãÿàÿáÿäÿâÿâÿâÿæÿáÿáÿáÿÞÿáÿÙÿÚÿÚÿÙÿØÿÚÿÙÿÖÿÕÿÖÿÙÿÛÿÚÿÎÿÏÿÎÿÑÿÑÿÏÿÐÿÒÿÓÿÑÿÏÿÐÿÑÿÌÿÉÿÇÿÈÿÃÿÃÿÈÿÇÿÆÿÉÿÈÿÁÿÀÿÂÿ¿ÿ¼ÿ¿ÿÀÿ¿ÿ¹ÿ¾ÿÀÿ¼ÿ¹ÿÁÿ¿ÿÀÿ¿ÿ¾ÿ¼ÿ¼ÿ¼ÿ½ÿ»ÿ¿ÿ»ÿ¹ÿºÿ¹ÿ·ÿ¹ÿ¸ÿ¼ÿ½ÿ¼ÿ´ÿ³ÿ¶ÿ¸ÿ¸ÿµÿ¸ÿ¹ÿºÿ´ÿ¶ÿµÿ²ÿ­ÿ­ÿ°ÿ°ÿ±ÿ®ÿªÿ­ÿ­ÿ¨ÿªÿ®ÿ«ÿ§ÿ­ÿ­ÿ©ÿ­ÿ©ÿ«ÿ«ÿ§ÿ¢ÿ¦ÿ§ÿ¨ÿ¥ÿ¥ÿ«ÿ©ÿ«ÿ¨ÿ¦ÿ©ÿ®ÿ©ÿ«ÿ®ÿ®ÿ¯ÿ¨ÿ­ÿ­ÿ®ÿ®ÿ®ÿ¯ÿ²ÿ®ÿ­ÿ±ÿ³ÿ®ÿ¬ÿ¨ÿ§ÿ©ÿªÿ©ÿ­ÿ¨ÿ£ÿ§ÿªÿ©ÿ¦ÿ§ÿ¦ÿ§ÿ£ÿ©ÿ¬ÿ®ÿ¬ÿ¯ÿ®ÿ­ÿ­ÿ¬ÿ§ÿ«ÿªÿ©ÿ©ÿ¬ÿ®ÿ©ÿ¨ÿ¨ÿªÿ¥ÿ«ÿ­ÿ­ÿ­ÿ¬ÿ®ÿ°ÿ²ÿ±ÿ­ÿ­ÿ¯ÿ³ÿ¯ÿ°ÿ®ÿ¯ÿ¯ÿ¬ÿ­ÿ°ÿ¬ÿ¦ÿ§ÿ©ÿ¯ÿ®ÿ­ÿ§ÿ©ÿ¨ÿ©ÿ¥ÿ¨ÿªÿ¨ÿ§ÿ«ÿªÿ©ÿ¬ÿ®ÿ­ÿ±ÿ®ÿ°ÿ²ÿ±ÿ´ÿ³ÿ·ÿ¶ÿºÿµÿ´ÿ³ÿ°ÿ®ÿ®ÿ´ÿ¶ÿµÿ²ÿ³ÿ·ÿ´ÿµÿ¶ÿ»ÿ´ÿ·ÿ·ÿ»ÿ¹ÿ¼ÿ»ÿµÿ³ÿ´ÿµÿ°ÿµÿ¶ÿ®ÿ¯ÿ¯ÿ³ÿ±ÿ«ÿ¬ÿ®ÿ¬ÿ¬ÿ°ÿ¯ÿ«ÿ§ÿ©ÿ­ÿ¬ÿ©ÿ®ÿ²ÿ¬ÿ©ÿ®ÿ¯ÿ¯ÿ²ÿ´ÿ³ÿ±ÿ¯ÿ¬ÿ¬ÿ¬ÿ®ÿ±ÿ­ÿªÿ§ÿ§ÿ¨ÿ©ÿ¤ÿ¤ÿ¨ÿ¥ÿŸÿžÿ ÿ£ÿ¢ÿ¤ÿ¥ÿ£ÿ£ÿ¤ÿ¤ÿªÿ§ÿªÿ­ÿ«ÿ©ÿ¨ÿ¨ÿ¥ÿ¨ÿ«ÿ®ÿ¦ÿ¥ÿ¥ÿ¦ÿ§ÿªÿ«ÿ£ÿ¨ÿ¬ÿ§ÿ¥ÿ¨ÿ¦ÿ§ÿ¥ÿ¥ÿ¤ÿ¥ÿ¥ÿ¤ÿ¢ÿ ÿ ÿ¡ÿ¡ÿ ÿ›ÿŸÿ¢ÿžÿ˜ÿ›ÿ¡ÿÿŸÿ¡ÿ ÿ¡ÿ ÿÿ—ÿ–ÿ˜ÿžÿžÿÿ¢ÿÿœÿšÿ—ÿšÿ›ÿžÿžÿšÿšÿœÿšÿÿšÿœÿ™ÿ–ÿ•ÿšÿÿžÿŸÿ£ÿ¢ÿ™ÿšÿ ÿšÿœÿœÿžÿ˜ÿ›ÿ ÿ˜ÿšÿ™ÿ˜ÿ—ÿ—ÿ”ÿ•ÿ–ÿ•ÿ”ÿ—ÿ™ÿ—ÿ–ÿ–ÿ•ÿ—ÿ—ÿ“ÿ•ÿÿÿžÿ™ÿ™ÿœÿ›ÿ™ÿšÿœÿÿŸÿŸÿÿœÿšÿÿ ÿ ÿ ÿŸÿŸÿ£ÿ¨ÿ£ÿ¡ÿ ÿÿžÿžÿÿžÿŸÿœÿÿžÿ ÿ¥ÿ¦ÿ¡ÿ¡ÿ¤ÿÿ¢ÿ¡ÿ§ÿ¨ÿ¥ÿ¤ÿ ÿ¤ÿ¥ÿ¢ÿ›ÿÿ ÿ¡ÿ ÿœÿ›ÿŸÿœÿÿœÿŸÿ¡ÿ¡ÿ¢ÿ¡ÿ ÿŸÿ¡ÿœÿŸÿœÿ›ÿÿšÿšÿšÿœÿ˜ÿÿ ÿ¢ÿÿÿžÿŸÿŸÿ¢ÿ¨ÿ¢ÿ¥ÿ ÿžÿ¡ÿ¢ÿ¢ÿ¢ÿ©ÿ©ÿ¦ÿ£ÿ£ÿ¤ÿ¢ÿ£ÿ£ÿ¡ÿ£ÿ ÿ¦ÿ§ÿ¥ÿ§ÿ¨ÿ£ÿ£ÿ¡ÿ¢ÿ ÿ¢ÿ£ÿ¥ÿ¤ÿ£ÿ¦ÿ£ÿ¢ÿ¢ÿ¤ÿ¦ÿ¦ÿ£ÿ ÿ¨ÿ¦ÿ¥ÿ¨ÿ¬ÿ®ÿ«ÿ¬ÿ®ÿ¬ÿªÿ®ÿ«ÿªÿ­ÿ©ÿ¬ÿ¯ÿ­ÿªÿ­ÿ¬ÿ¯ÿ°ÿ±ÿ³ÿµÿ®ÿ®ÿ­ÿ²ÿ®ÿ«ÿ¬ÿ°ÿ¬ÿ¬ÿ¬ÿ¬ÿ±ÿ®ÿ°ÿµÿ·ÿ¶ÿºÿ¶ÿµÿ³ÿµÿ³ÿ³ÿ³ÿ±ÿµÿ°ÿ³ÿ±ÿ²ÿ´ÿ¯ÿ±ÿ¬ÿ«ÿ¬ÿ¯ÿ¯ÿ±ÿ²ÿ³ÿ³ÿ´ÿ·ÿºÿ·ÿ¸ÿ·ÿµÿ²ÿµÿ¸ÿ¿ÿÀÿ½ÿºÿ¸ÿºÿ»ÿ¾ÿ¿ÿ½ÿ¼ÿ½ÿ½ÿÀÿÂÿ½ÿÁÿÂÿÆÿÆÿÉÿÊÿËÿÅÿÅÿÇÿÅÿËÿÊÿÊÿËÿÈÿËÿÈÿËÿÉÿÌÿÊÿÎÿÌÿÏÿÑÿÔÿÕÿØÿÒÿÕÿÏÿÍÿÎÿÒÿÕÿØÿÖÿÖÿÑÿÑÿÎÿÒÿÖÿÒÿÎÿÍÿÍÿÏÿÍÿÌÿÎÿÍÿÎÿÏÿÑÿÏÿÍÿÒÿÑÿÎÿÑÿÒÿÒÿÕÿÔÿÚÿ×ÿÖÿÙÿÙÿÝÿÞÿÙÿÜÿáÿßÿÛÿÜÿÙÿÛÿÛÿÛÿÚÿÙÿÞÿÛÿÒÿÙÿÞÿáÿßÿÜÿÜÿàÿßÿàÿßÿÜÿáÿÞÿÜÿÜÿÞÿÙÿÚÿàÿçÿæÿæÿãÿáÿáÿçÿèÿåÿäÿàÿäÿçÿêÿëÿéÿäÿæÿåÿâÿçÿðÿíÿëÿçÿéÿæÿèÿæÿìÿéÿêÿíÿéÿéÿéÿêÿêÿèÿèÿêÿêÿêÿèÿçÿåÿæÿìÿîÿêÿðÿïÿðÿòÿðÿìÿîÿèÿéÿæÿåÿçÿéÿìÿíÿíÿíÿíÿëÿñÿöÿøÿûÿþÿþÿÿÿýÿûÿþÿÿÿýÿüÿøÿøÿýÿùÿöÿõÿõÿñÿõÿõÿùÿôÿ÷ÿôÿ÷ÿõÿùÿ÷ÿõÿôÿýÿþÿÿÿþÿýÿÿÿþÿýÿÿÿýÿüÿüÿþÿÿÿûÿ÷ÿöÿöÿýÿþÿÿÿýÿûÿúÿüÿÿÿÿÿüÿþÿÿÿûÿÿÿüÿþÿøÿüÿþÿüÿüÿùÿùÿûÿûÿûÿøÿÿÿùÿýÿ÷ÿ÷ÿýÿûÿôÿøÿüÿúÿøÿùÿùÿøÿôÿóÿóÿúÿ÷ÿôÿ÷ÿøÿùÿôÿþÿýÿøÿ÷ÿûÿýÿüÿøÿôÿ÷ÿøÿúÿúÿüÿýÿøÿöÿôÿöÿûÿóÿöÿûÿùÿøÿýÿüÿýÿüÿþÿùÿûÿøÿõÿùÿùÿøÿùÿõÿõÿöÿôÿòÿöÿðÿôÿóÿôÿõÿöÿöÿðÿóÿõÿõÿõÿïÿîÿðÿòÿ÷ÿ÷ÿ÷ÿóÿõÿôÿõÿ÷ÿôÿôÿ÷ÿòÿðÿóÿñÿñÿôÿôÿóÿóÿöÿõÿ÷ÿöÿóÿòÿõÿùÿöÿõÿ÷ÿþÿûÿ÷ÿþÿýÿýÿüÿ÷ÿöÿúÿõÿüÿûÿüÿüÿüÿýÿþÿýÿÿÿÿÿ                                   !  !  !!" #%$"$'%&&''&'&&((,'''().))(,-.,0,02*121/013153566678;<>??A?A@<=??A?BBBB<;BD<><<::=;>@=>@?><8<C=>C@@A>==??@DDEBADDC>BEHHGIKKKLJGGGEHEEGHJIGGKJKNONPQNIGIJIKJECEGIFJKJINONSROQMOUSPPPSOKNOPSORTSOVSRRSRWVUPSNTRTTQPOMURROOLPOUYUUPMQRQOPQWSSRRSNOQRTXX[XVQOTOQTVWTTWSVXYYYWXT[`YVVSRTSTSOPONPMNOLNMKRNNQNNTUOOLJHGHKLKGHC??HIFFEEEBJKKEFBAGHFGCBEFFBEOGHHGKGHNMLKLQQRNMLMPNMPOMQQNKMMOOKJGIFGJHGFDINIHHFHIHHMLKKIDDABGIF@AEFGBA>ADEDCDCDCJIGNIIKKJIJLLKHKKLHMUSOQMQSURTSRPKMSQNMOQRSQNOJIROQNNPPJFIOLMOKIJLMLHHKLNNRLLOMNJHKIKKHKKGJEHHEIMQNGIKLKPIJKMJIEGIGFBHKIFCECGIHEECACAACEBB=<<==@?<;?::=85=>:6267893663357633//0/+,-*%)-****)&)-*%$##''%*'(# &$"!'"      þÿüÿýÿýÿÿÿúÿöÿþÿýÿÿÿÿÿøÿöÿ÷ÿôÿõÿõÿôÿòÿóÿòÿðÿïÿòÿïÿíÿíÿïÿñÿìÿéÿéÿêÿèÿìÿêÿêÿëÿçÿéÿèÿéÿæÿæÿâÿæÿéÿçÿæÿèÿèÿãÿæÿéÿçÿæÿçÿèÿåÿåÿéÿçÿçÿâÿáÿÛÿÞÿâÿßÿâÿáÿÝÿßÿÖÿÛÿÛÿÚÿÜÿÞÿÛÿÜÿÜÿÖÿ×ÿØÿ×ÿÔÿÖÿÑÿØÿÕÿÔÿÐÿÑÿÖÿ×ÿÒÿÒÿÑÿÒÿÔÿÒÿØÿÔÿÔÿÖÿÖÿÒÿÑÿÏÿÍÿËÿÍÿÍÿÍÿÎÿËÿÌÿËÿÊÿÈÿÅÿÆÿÊÿÊÿÇÿÄÿÈÿÃÿÅÿÈÿÈÿÈÿÈÿÇÿËÿÎÿËÿÑÿÍÿÑÿÎÿÑÿÑÿÏÿÌÿÐÿÕÿÒÿÐÿÓÿÒÿÏÿÓÿÖÿÔÿØÿÛÿØÿÔÿÔÿÕÿØÿØÿÙÿÛÿÚÿØÿÛÿÚÿÚÿÛÿÙÿàÿÝÿÞÿÞÿÞÿÞÿÞÿÛÿØÿÛÿÜÿÚÿÛÿÜÿÜÿ×ÿÔÿÓÿÚÿ×ÿÙÿÜÿÛÿ×ÿÖÿÔÿØÿÛÿ×ÿÐÿÔÿÙÿÛÿØÿÚÿÞÿàÿÜÿÝÿßÿÛÿàÿãÿãÿåÿãÿßÿäÿãÿÞÿåÿäÿèÿåÿàÿàÿãÿãÿçÿíÿîÿìÿêÿìÿéÿìÿëÿëÿêÿîÿñÿôÿôÿóÿðÿíÿìÿòÿôÿòÿõÿøÿøÿùÿóÿõÿòÿøÿøÿôÿòÿöÿóÿõÿ÷ÿúÿýÿ÷ÿñÿîÿñÿóÿòÿðÿòÿðÿòÿõÿ÷ÿöÿöÿ÷ÿóÿîÿîÿðÿïÿñÿöÿôÿòÿðÿóÿôÿñÿñÿðÿôÿóÿ÷ÿóÿõÿ÷ÿöÿ÷ÿöÿóÿøÿôÿñÿóÿöÿùÿúÿúÿúÿýÿûÿúÿüÿúÿøÿúÿüÿþÿûÿüÿÿÿÿÿýÿûÿÿÿýÿüÿüÿýÿýÿþÿþÿúÿýÿùÿùÿúÿûÿÿÿþÿýÿúÿüÿùÿöÿýÿÿÿÿÿûÿøÿúÿûÿúÿþÿÿÿýÿûÿüÿûÿüÿýÿþÿÿÿúÿþÿûÿúÿþÿüÿúÿûÿûÿûÿÿÿýÿúÿüÿýÿüÿùÿøÿýÿûÿùÿõÿöÿ÷ÿöÿúÿûÿÿÿøÿüÿúÿþÿüÿýÿúÿÿÿþÿüÿýÿøÿøÿýÿÿÿûÿúÿþÿýÿûÿýÿÿÿúÿþÿüÿúÿûÿúÿúÿüÿýÿûÿöÿ÷ÿûÿùÿùÿûÿøÿûÿüÿøÿûÿøÿòÿóÿùÿ÷ÿùÿÿÿüÿûÿýÿüÿøÿüÿüÿùÿýÿÿÿüÿþÿýÿýÿûÿýÿûÿùÿûÿúÿøÿüÿÿÿüÿÿÿýÿÿÿþÿüÿöÿöÿûÿþÿ÷ÿöÿöÿøÿóÿìÿïÿòÿíÿðÿòÿóÿðÿìÿéÿìÿîÿóÿõÿøÿôÿïÿòÿôÿóÿïÿôÿòÿñÿðÿñÿñÿðÿìÿêÿëÿðÿóÿòÿîÿïÿðÿïÿóÿðÿõÿôÿ÷ÿøÿòÿðÿîÿòÿöÿòÿðÿóÿõÿôÿöÿõÿúÿùÿ÷ÿùÿøÿóÿòÿöÿøÿùÿ÷ÿôÿõÿ÷ÿõÿóÿõÿóÿ÷ÿõÿóÿòÿóÿõÿöÿòÿóÿôÿñÿöÿ÷ÿøÿôÿöÿ÷ÿ÷ÿöÿôÿôÿõÿöÿóÿñÿòÿõÿõÿøÿõÿõÿõÿôÿôÿöÿùÿòÿñÿóÿïÿñÿõÿõÿñÿîÿëÿìÿðÿóÿôÿïÿðÿñÿõÿõÿ÷ÿöÿùÿóÿõÿôÿôÿõÿþÿþÿûÿüÿ÷ÿôÿõÿöÿõÿøÿýÿûÿ÷ÿôÿõÿóÿôÿõÿòÿñÿöÿñÿðÿîÿñÿðÿòÿôÿòÿíÿìÿîÿîÿïÿìÿçÿéÿçÿèÿêÿåÿáÿçÿâÿäÿæÿâÿåÿáÿãÿãÿâÿáÿÛÿÛÿÝÿÝÿÜÿÚÿÝÿÛÿÚÿÜÿ×ÿÛÿÙÿÖÿÔÿÔÿÙÿÚÿÛÿÛÿÛÿÖÿÙÿÕÿØÿÕÿØÿÖÿÑÿÒÿÖÿÔÿÓÿÓÿÕÿÖÿØÿÛÿÔÿÔÿÓÿ×ÿÕÿÔÿÓÿÐÿÖÿÓÿÔÿÔÿÖÿÖÿØÿØÿÚÿØÿÙÿÛÿÚÿ×ÿ×ÿÙÿÜÿÖÿØÿÞÿØÿÙÿÙÿÚÿÖÿÔÿÚÿÙÿ×ÿØÿÑÿÑÿÐÿÓÿÓÿÓÿÑÿÒÿÔÿÓÿÏÿÏÿÍÿÌÿÍÿÑÿËÿËÿÍÿÉÿÍÿËÿÈÿËÿÎÿÌÿÉÿÊÿÉÿÌÿÏÿÍÿËÿÎÿËÿÊÿËÿÈÿÉÿÇÿÈÿÍÿÍÿÒÿÎÿÌÿËÿÍÿËÿÍÿÍÿÎÿÌÿËÿÎÿÎÿÎÿÏÿÐÿÌÿÊÿÇÿÆÿÊÿÈÿÁÿÃÿÄÿÆÿÅÿÈÿÆÿÉÿÆÿÆÿÃÿÄÿÃÿÂÿÇÿÌÿÌÿÈÿÉÿËÿÅÿÆÿÌÿÊÿÌÿËÿÎÿÉÿÂÿÅÿÂÿÀÿ¿ÿ½ÿ¿ÿÁÿÄÿÄÿÅÿÄÿÂÿÇÿÄÿÉÿÅÿÅÿÊÿËÿËÿËÿÉÿÊÿÉÿÍÿÊÿÊÿÌÿÏÿÐÿÐÿÑÿÊÿÇÿÆÿÇÿÆÿÃÿÄÿÃÿÄÿÆÿÉÿÊÿÃÿÅÿÆÿÆÿÇÿÍÿÇÿÇÿÉÿÆÿËÿËÿÈÿÉÿÎÿÊÿÇÿËÿÌÿÍÿÐÿÑÿÒÿÏÿÌÿËÿÇÿËÿËÿÌÿÉÿÇÿÉÿÌÿÉÿÈÿÉÿÇÿËÿËÿÎÿÈÿËÿËÿËÿÎÿÊÿÄÿÅÿÇÿÇÿÄÿÌÿÍÿËÿÊÿÉÿÃÿÁÿ¿ÿÀÿÆÿÃÿÃÿÃÿÀÿÄÿ¿ÿÅÿÃÿÀÿ¾ÿÁÿÂÿÃÿÇÿÆÿÉÿÉÿÌÿÇÿÇÿÈÿÆÿËÿÆÿÇÿÉÿÌÿÏÿËÿÈÿÈÿÅÿÆÿÇÿÈÿÉÿÍÿÌÿËÿÊÿÉÿËÿËÿÇÿÅÿÇÿÅÿÅÿÊÿËÿÊÿÌÿÌÿÇÿÊÿÇÿÈÿÅÿÃÿÇÿÊÿÊÿËÿËÿÈÿÆÿÅÿÄÿ¿ÿÂÿÁÿÂÿÅÿÉÿÃÿÀÿÃÿÃÿ¿ÿ¾ÿÃÿÄÿÇÿÉÿÆÿÈÿ¿ÿ¾ÿÂÿÅÿÃÿÉÿÆÿÆÿÌÿÌÿÇÿÅÿÃÿÅÿÇÿÆÿÅÿÉÿÈÿÈÿÊÿÏÿÍÿÌÿÐÿÒÿÑÿÓÿÚÿÛÿÜÿÜÿÙÿÜÿØÿØÿ×ÿÙÿÙÿÛÿÛÿÜÿÞÿÛÿÙÿÝÿßÿßÿÝÿáÿãÿàÿÝÿàÿáÿÞÿàÿäÿçÿáÿáÿäÿêÿëÿàÿåÿéÿãÿçÿæÿçÿåÿãÿäÿãÿèÿçÿâÿçÿìÿçÿåÿæÿäÿçÿìÿèÿêÿëÿæÿæÿìÿìÿéÿéÿîÿïÿïÿðÿîÿèÿèÿðÿïÿïÿñÿïÿïÿîÿíÿñÿðÿïÿïÿñÿòÿóÿòÿöÿ÷ÿöÿ÷ÿöÿöÿùÿ÷ÿõÿöÿõÿñÿóÿôÿòÿöÿõÿôÿõÿùÿøÿöÿúÿùÿÿÿúÿþÿúÿýÿÿÿÿÿýÿþÿÿÿÿÿûÿüÿúÿùÿøÿøÿùÿùÿùÿþÿúÿýÿüÿûÿüÿøÿûÿüÿýÿþÿþÿúÿûÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿýÿýÿ ÿÿ ÿÿþÿþÿýÿþÿýÿýÿþÿÿÿþÿÿÿÿÿúÿúÿýÿûÿüÿþÿúÿúÿûÿúÿûÿùÿ÷ÿ÷ÿõÿöÿóÿóÿôÿõÿóÿöÿñÿòÿóÿñÿóÿîÿîÿñÿñÿóÿóÿðÿìÿìÿñÿñÿòÿòÿñÿíÿóÿöÿóÿôÿôÿñÿðÿîÿñÿðÿðÿîÿæÿíÿêÿèÿéÿçÿæÿæÿéÿçÿæÿíÿëÿåÿêÿèÿéÿéÿêÿéÿëÿðÿïÿëÿçÿçÿéÿñÿïÿìÿêÿßÿàÿàÿáÿäÿäÿàÿãÿÞÿÙÿÛÿßÿßÿàÿÝÿÞÿÛÿÝÿÝÿàÿÞÿáÿãÿàÿäÿàÿÜÿØÿØÿÞÿÜÿÜÿØÿØÿÖÿÕÿÖÿÚÿÛÿÝÿáÿÝÿÝÿÞÿÝÿÛÿàÿßÿÚÿÝÿÜÿÛÿÛÿÝÿ×ÿØÿÚÿÚÿØÿÖÿ×ÿØÿÔÿØÿØÿØÿÙÿÖÿÕÿÙÿÛÿØÿÚÿÜÿÚÿÙÿÜÿØÿØÿÙÿÜÿÙÿÝÿáÿâÿÝÿáÿãÿãÿãÿáÿÝÿâÿÞÿßÿßÿäÿãÿâÿáÿàÿßÿáÿáÿáÿæÿáÿãÿâÿàÿáÿàÿçÿéÿêÿêÿéÿçÿåÿãÿåÿêÿçÿçÿéÿëÿëÿçÿæÿãÿéÿéÿæÿâÿéÿåÿæÿçÿíÿðÿïÿíÿðÿðÿîÿïÿòÿïÿíÿîÿìÿðÿïÿëÿìÿìÿìÿéÿëÿëÿçÿêÿêÿêÿêÿéÿêÿëÿêÿíÿíÿìÿêÿëÿëÿïÿéÿëÿìÿíÿñÿñÿóÿñÿïÿïÿñÿòÿñÿïÿëÿñÿôÿöÿïÿîÿîÿðÿðÿíÿëÿíÿîÿêÿíÿïÿïÿëÿñÿîÿóÿðÿïÿîÿíÿîÿëÿïÿôÿòÿíÿðÿôÿóÿòÿñÿðÿðÿêÿìÿîÿîÿíÿîÿêÿîÿïÿîÿïÿðÿòÿïÿïÿðÿðÿîÿèÿïÿòÿõÿðÿòÿñÿíÿëÿëÿðÿïÿíÿìÿêÿéÿëÿîÿíÿêÿêÿïÿîÿíÿîÿíÿîÿëÿêÿéÿéÿìÿíÿìÿêÿîÿôÿêÿïÿòÿíÿìÿëÿéÿéÿçÿäÿèÿçÿêÿêÿêÿêÿâÿíÿêÿæÿêÿçÿëÿéÿêÿèÿèÿäÿêÿëÿìÿðÿçÿæÿèÿðÿëÿèÿðÿïÿíÿîÿíÿïÿðÿñÿïÿîÿðÿëÿíÿòÿòÿñÿðÿñÿðÿñÿóÿïÿòÿóÿóÿôÿôÿöÿ÷ÿùÿóÿöÿôÿ÷ÿóÿòÿõÿòÿöÿôÿõÿòÿîÿðÿðÿêÿïÿíÿïÿèÿêÿëÿåÿäÿçÿéÿêÿçÿéÿéÿåÿãÿâÿâÿãÿåÿâÿâÿÞÿâÿáÿæÿßÿàÿßÿâÿàÿçÿâÿâÿãÿãÿâÿãÿâÿÞÿáÿåÿäÿÝÿâÿâÿÛÿÛÿàÿáÿÜÿÞÿßÿáÿâÿÞÿÜÿÜÿÞÿãÿâÿÞÿ×ÿÝÿÛÿÛÿÛÿÛÿ×ÿÜÿàÿÛÿÝÿÜÿÛÿÙÿÙÿÙÿÜÿÚÿÖÿÔÿÕÿÖÿÔÿ×ÿÒÿÕÿÎÿÎÿÑÿÌÿÐÿÒÿÒÿÕÿÕÿ×ÿÓÿÐÿØÿÛÿ×ÿÕÿØÿÔÿ×ÿÛÿÜÿÙÿÜÿÝÿÚÿÕÿÖÿÒÿÒÿÕÿÖÿÖÿ×ÿÛÿØÿÕÿÖÿÔÿÕÿÚÿÝÿÞÿÜÿÛÿÚÿÛÿ×ÿØÿÛÿÜÿßÿßÿÛÿßÿØÿÚÿÜÿãÿáÿáÿÛÿÜÿÞÿàÿÜÿãÿãÿÞÿÞÿÞÿÞÿæÿæÿâÿáÿáÿâÿçÿäÿãÿçÿëÿäÿæÿåÿäÿäÿçÿæÿéÿéÿéÿêÿïÿéÿèÿíÿïÿðÿîÿñÿòÿñÿòÿøÿüÿûÿüÿýÿþÿýÿûÿùÿúÿüÿÿÿûÿþÿøÿúÿþÿÿÿ     ! ! ## $##$$',*((%(,%()())*-,-,)).,4334:<2467;=><987<==@<DCBA@=?EDDGFEKIFFFFECFIIOIGHJILJMQTSPSTRNNQNPVTSTXXUWYYVTWWXZYX[[XVY]]\Z[VZ]]\^_accacc^__b_b````ccbba__]b_\`acdb`[ad__\[]]]`_bedbcd^[Z`_\Z]X]_]^_\\_dbcb^[]`cXZZ`]^Y\^^[\\^Z_\YZX][Y^[]dd_`c^c^Z\ZX]\_[TXVXWVYVWTSSPRZXYTWXWZ]`^\Z[YZ[a\^W[^_aZY\^^\]]\ZZSU[Z[ad`_][W^[ZWY\\_]]\[]Z\]]\\\XX[\[Y[^[^ZUX][Z]YSXZ[XWXWXVYXXXZVWYSSVTURTUMPPVTNSSRSUTRQPPRPNOKKKKNLPOOPMMJJHCHFHKF@@GEEEBCAE@EC;>FAAD>=DB?A?DA<=CCFECDHHAA>@DACEDCBBBA@=@>AA;<=9847=<7897501321650363345770457,+040,./-323/.///.00133.1/,+/.++,-(.-01,.,+)*-,,/3.*.-0/-*-/*++%()-+(%"--**,.)+.*!  #  !## #'!%!%##!#"$'#" "      ÿÿþÿýÿüÿÿÿûÿþÿþÿþÿýÿüÿÿÿýÿÿÿþÿþÿúÿüÿþÿüÿÿÿùÿúÿþÿüÿýÿýÿûÿùÿ÷ÿøÿôÿøÿûÿõÿùÿôÿñÿóÿôÿñÿñÿðÿðÿóÿóÿñÿïÿòÿóÿïÿôÿóÿïÿòÿòÿðÿðÿõÿðÿîÿðÿòÿòÿóÿñÿôÿòÿôÿóÿòÿóÿøÿïÿñÿòÿ÷ÿ÷ÿùÿöÿñÿòÿöÿ÷ÿ÷ÿøÿöÿöÿñÿðÿðÿðÿñÿ÷ÿöÿ÷ÿ÷ÿøÿôÿôÿóÿòÿðÿðÿðÿêÿíÿñÿîÿíÿðÿñÿðÿðÿðÿðÿíÿðÿïÿ÷ÿôÿóÿñÿîÿëÿêÿìÿëÿëÿêÿçÿêÿéÿèÿäÿäÿèÿåÿãÿáÿâÿéÿèÿåÿãÿãÿåÿäÿäÿæÿäÿâÿäÿåÿêÿêÿçÿéÿéÿéÿèÿçÿéÿèÿäÿâÿäÿäÿåÿçÿãÿäÿèÿãÿáÿåÿãÿâÿâÿäÿèÿèÿæÿåÿçÿéÿéÿïÿìÿçÿëÿêÿèÿæÿæÿçÿåÿçÿçÿãÿåÿçÿåÿäÿæÿçÿçÿæÿèÿæÿæÿæÿåÿáÿãÿèÿèÿëÿêÿçÿåÿçÿçÿçÿéÿíÿëÿíÿìÿêÿïÿêÿëÿëÿìÿðÿîÿêÿëÿíÿêÿíÿïÿôÿôÿòÿñÿñÿîÿðÿðÿîÿîÿîÿôÿóÿôÿòÿðÿóÿôÿóÿîÿñÿðÿñÿõÿòÿðÿïÿêÿèÿîÿîÿìÿðÿñÿîÿêÿíÿíÿñÿîÿîÿïÿîÿíÿîÿêÿêÿìÿíÿíÿðÿíÿìÿêÿëÿëÿëÿîÿîÿïÿðÿñÿïÿóÿðÿõÿîÿíÿîÿíÿîÿïÿïÿêÿìÿïÿíÿðÿñÿìÿæÿæÿéÿèÿèÿìÿèÿæÿäÿéÿèÿæÿäÿâÿàÿâÿäÿãÿåÿäÿåÿâÿãÿæÿéÿëÿåÿàÿâÿãÿæÿçÿåÿãÿäÿáÿàÿÝÿÜÿßÿáÿÝÿÜÿÞÿßÿÞÿâÿßÿÛÿÝÿÚÿßÿÚÿÜÿÚÿÝÿÚÿÜÿÖÿÖÿ×ÿÙÿÛÿÛÿÜÿáÿßÿÞÿáÿßÿãÿæÿâÿãÿæÿåÿâÿÛÿÛÿáÿáÿÞÿÞÿáÿÜÿåÿèÿãÿãÿáÿßÿÛÿÜÿÞÿßÿáÿÞÿÜÿÛÿÝÿÜÿØÿ×ÿÝÿÞÿÝÿÝÿÝÿàÿäÿÞÿáÿãÿÝÿÜÿãÿåÿåÿâÿãÿãÿåÿäÿÞÿàÿÝÿáÿàÿÙÿØÿÙÿÕÿØÿÛÿÜÿÜÿÙÿÛÿÖÿ×ÿØÿÕÿ×ÿÔÿÑÿÓÿ×ÿÕÿÔÿÔÿÖÿØÿÖÿÚÿ×ÿØÿÙÿÖÿÖÿ×ÿÒÿÏÿÒÿÎÿÎÿÐÿÐÿÎÿÎÿÎÿÊÿÈÿÌÿÎÿÎÿÌÿÒÿÏÿÑÿÓÿÐÿÌÿÑÿÑÿÎÿÑÿÒÿÒÿÏÿÎÿÐÿÓÿÑÿÑÿÊÿËÿÍÿÍÿÎÿÍÿËÿÊÿÈÿÌÿÌÿÌÿÈÿÆÿÇÿÆÿÄÿÅÿÁÿÇÿÇÿÇÿÉÿÊÿËÿÌÿÊÿËÿÌÿÅÿÇÿÆÿÆÿÃÿÁÿÁÿÀÿ¼ÿ¿ÿÂÿÃÿÀÿÀÿÁÿÁÿÂÿÅÿÄÿÂÿÂÿÀÿÁÿÀÿÂÿ¾ÿÅÿÂÿÁÿ¿ÿÁÿÂÿ¼ÿ»ÿ¾ÿ¾ÿ¾ÿÀÿ»ÿÀÿÄÿÁÿÁÿÂÿÀÿÂÿÃÿÁÿÀÿÀÿÁÿ¿ÿÂÿÀÿ¿ÿÃÿÂÿÄÿÁÿÄÿÂÿÀÿ¿ÿÁÿÂÿ¿ÿÀÿÀÿÂÿ¿ÿÂÿÁÿ¿ÿÁÿÃÿÂÿÄÿÀÿÁÿÅÿÃÿÇÿÄÿÈÿÉÿÇÿÅÿÃÿÄÿÃÿÄÿÁÿÁÿÂÿÁÿÂÿÀÿÁÿÂÿ½ÿ»ÿ½ÿ¼ÿ½ÿ»ÿ¸ÿ¸ÿ¼ÿ¼ÿ½ÿºÿ¼ÿ¿ÿ½ÿ¾ÿ½ÿ¿ÿ½ÿ¾ÿ»ÿ¾ÿÀÿÁÿ¾ÿ¹ÿ¾ÿÁÿ¾ÿ¸ÿ¼ÿ¿ÿ»ÿ½ÿ¾ÿ¾ÿ½ÿÀÿ¾ÿ¼ÿ¹ÿºÿºÿ¾ÿ½ÿÀÿ¿ÿÃÿÅÿÂÿÃÿ½ÿ¼ÿ½ÿÀÿ¿ÿ¾ÿÁÿ¿ÿºÿ»ÿ¶ÿ¼ÿ¾ÿ¹ÿ½ÿ¿ÿÃÿÀÿÃÿÁÿÀÿÁÿÂÿÀÿÁÿÃÿÀÿÁÿÀÿ½ÿ½ÿÁÿÁÿ¿ÿ¿ÿÀÿÂÿÁÿÀÿÁÿ¿ÿ»ÿÀÿÅÿÀÿÀÿÂÿÁÿ½ÿ¾ÿÂÿÀÿÀÿÂÿ¿ÿ¾ÿÅÿ¿ÿ¼ÿ¾ÿÁÿ¿ÿÂÿÆÿ¾ÿÂÿ¿ÿ¿ÿ½ÿ½ÿÁÿÁÿ¿ÿ½ÿ¾ÿÁÿ¿ÿ¸ÿ¸ÿ¿ÿ¼ÿ»ÿºÿ¸ÿ¸ÿ½ÿÀÿÃÿÃÿÁÿ¿ÿ½ÿ»ÿ¾ÿÃÿÃÿÄÿÂÿ¿ÿ½ÿ¼ÿ½ÿÀÿ¾ÿ½ÿ¿ÿ¿ÿ¾ÿ»ÿ¹ÿ»ÿ¹ÿ¼ÿ¹ÿ¸ÿ¾ÿ½ÿ»ÿ¹ÿ¹ÿ¹ÿ·ÿ¶ÿ¸ÿ¶ÿ·ÿ¹ÿ·ÿ·ÿ»ÿ¹ÿ´ÿ¶ÿ¶ÿ®ÿ¯ÿ°ÿ²ÿµÿ³ÿ´ÿ´ÿ·ÿ·ÿ·ÿ·ÿºÿºÿ¿ÿ»ÿ¹ÿºÿ¼ÿ¸ÿ·ÿºÿ¾ÿºÿ»ÿºÿ³ÿ´ÿºÿ½ÿ·ÿµÿ·ÿ³ÿ±ÿ®ÿ³ÿ³ÿ´ÿ±ÿ±ÿ´ÿ³ÿµÿ¶ÿ³ÿ²ÿ¯ÿ«ÿ´ÿ°ÿ²ÿ®ÿ°ÿµÿ´ÿ°ÿ²ÿ²ÿ®ÿ±ÿµÿ±ÿ³ÿ¶ÿ¶ÿµÿ³ÿ±ÿµÿ³ÿ±ÿ²ÿ³ÿ·ÿ´ÿ¶ÿ¶ÿ´ÿ·ÿ´ÿµÿ²ÿ¹ÿ¶ÿ¶ÿ¶ÿµÿµÿ´ÿ¶ÿµÿ²ÿ®ÿ±ÿ´ÿ³ÿ·ÿ³ÿ³ÿ³ÿ³ÿ²ÿ´ÿ³ÿ´ÿ±ÿ²ÿ³ÿ´ÿ²ÿ²ÿ´ÿ¸ÿ¹ÿ´ÿ¸ÿ·ÿ¸ÿ·ÿ¸ÿ½ÿ»ÿÂÿ¿ÿÀÿÀÿÃÿÂÿÂÿ½ÿ¾ÿ¿ÿÅÿÇÿËÿÉÿÆÿÍÿÐÿÌÿËÿÊÿÍÿÔÿÕÿ×ÿÓÿÐÿÔÿÔÿÕÿÕÿ×ÿÞÿÜÿÛÿÝÿàÿÝÿÛÿÙÿßÿÞÿßÿàÿãÿßÿÞÿáÿãÿçÿèÿãÿàÿáÿçÿçÿçÿåÿëÿîÿíÿïÿèÿêÿèÿíÿìÿëÿëÿðÿðÿïÿôÿòÿòÿøÿôÿôÿóÿòÿõÿôÿõÿöÿùÿûÿúÿôÿ÷ÿõÿöÿùÿùÿõÿùÿøÿøÿýÿýÿùÿùÿúÿýÿÿÿ     &#%"$&')))'%&**+*(*-+*,1//304566:8;9=5384:;9:<:8:;75468:??>?>>??DDDBFEFDEHJINJJLOLLMOJMLOSMLONLMOPPMMLJKHHIIFEHHJMMNNLLMINNMLNQNPQQTUUTSTRTQPOPPQRRTPPOMOLJNORQMPSSSSPVVVUPLNPQRPOPJMOQLLIIMMMNNNKIJJMKNNMMJIHIJNKKJLMMMKLQOMLJRPOSPQMLMPMOLJKQQPOOQPNPPPSTTRWSUUTSVVWTWTVVQRSTTTSRUVTRTUUY[XWWXYVZ]\\^ZZ^]]^][Z\\WVY\\[\Z\\``_]_^`_`Z\Z[]]^^_Z[X\]c^\YWVXUWWXWYZ[[ZX[]]_[[\YZWUUX\\ZYY]]YVW[YVWWUXYVX[WWVXXWZWUVYXVTUZ][]Z\\\]YZZZ\[X]ZX[WTUURRNOLMLLOSRNJJNJLKNNMLMHIFGJHIMKJGIFFGHIIJHHIHKHKGCECBBACAAA=@@A>@@C?CCBD?B>===>B@>A==97997753753588961469997:755325585+./4/1/..*&&'''(*''+(&%%'"!"##$&"$$!     ÿÿÿÿÿÿÿÿýÿýÿüÿýÿþÿÿÿüÿþÿþÿýÿþÿüÿüÿÿÿÿÿüÿúÿüÿûÿùÿúÿþÿúÿøÿ÷ÿøÿùÿûÿöÿöÿùÿúÿóÿõÿõÿóÿöÿ÷ÿ÷ÿöÿõÿóÿõÿõÿòÿòÿóÿ÷ÿøÿõÿöÿõÿðÿôÿöÿüÿûÿ÷ÿóÿóÿõÿöÿùÿøÿöÿýÿÿÿÿÿýÿøÿ÷ÿùÿöÿøÿùÿüÿøÿúÿüÿüÿùÿùÿ÷ÿýÿýÿýÿúÿýÿýÿÿÿÿÿüÿüÿýÿûÿúÿûÿýÿþÿþÿýÿûÿüÿÿÿýÿÿÿþÿûÿûÿúÿÿÿúÿùÿ÷ÿýÿþÿÿÿþÿýÿüÿÿÿûÿûÿøÿöÿúÿöÿòÿòÿòÿôÿõÿùÿøÿ÷ÿôÿõÿøÿþÿøÿòÿóÿòÿòÿöÿùÿòÿóÿõÿóÿòÿõÿõÿõÿöÿòÿôÿóÿôÿøÿöÿöÿôÿôÿöÿüÿûÿ÷ÿøÿùÿøÿ÷ÿõÿôÿöÿûÿùÿ÷ÿôÿõÿøÿ÷ÿõÿòÿ÷ÿóÿõÿøÿ÷ÿöÿóÿóÿ÷ÿõÿóÿõÿóÿòÿôÿöÿ÷ÿöÿöÿõÿõÿõÿñÿôÿøÿöÿôÿôÿñÿõÿóÿôÿòÿëÿìÿïÿìÿíÿíÿòÿïÿïÿïÿîÿíÿîÿíÿíÿñÿïÿíÿðÿòÿðÿòÿñÿóÿóÿòÿòÿðÿòÿðÿðÿòÿîÿñÿðÿíÿíÿîÿîÿóÿíÿîÿîÿìÿïÿðÿïÿðÿòÿïÿðÿñÿðÿíÿëÿìÿëÿíÿñÿñÿîÿìÿîÿñÿðÿîÿïÿíÿëÿíÿîÿïÿðÿìÿéÿéÿçÿèÿåÿéÿåÿâÿçÿçÿäÿàÿáÿãÿáÿÞÿÞÿßÿàÿâÿåÿâÿâÿßÿÝÿàÿßÿâÿáÿßÿÙÿÕÿÚÿÜÿØÿØÿÛÿÞÿÞÿÞÿÚÿÜÿÚÿØÿÝÿÝÿÙÿ×ÿ×ÿ×ÿÚÿÙÿÜÿÛÿÛÿÙÿ×ÿÖÿÙÿÙÿØÿÖÿØÿÔÿÖÿÖÿÔÿÔÿÒÿÏÿÔÿÖÿÔÿÐÿÖÿÑÿÓÿÕÿÔÿ×ÿÕÿÔÿÑÿÖÿÓÿÓÿÑÿÑÿÒÿ×ÿÔÿÒÿÖÿÔÿÓÿÏÿÑÿÔÿÓÿÕÿÓÿÐÿÐÿÓÿÔÿÑÿÒÿÕÿÑÿÍÿÎÿÎÿÎÿÑÿÍÿÇÿÇÿÌÿÊÿÌÿÏÿÈÿÈÿÊÿÊÿÊÿÇÿÆÿÄÿÈÿÉÿÅÿÆÿÆÿÆÿÃÿÅÿÄÿÇÿÄÿÃÿÂÿÂÿÅÿÅÿÅÿÆÿÇÿÆÿÂÿÄÿÂÿÀÿÃÿÄÿÁÿ¿ÿÁÿÃÿÁÿÁÿÀÿ¿ÿÁÿÂÿÃÿÁÿÂÿÂÿÂÿÁÿÁÿÂÿÅÿÄÿÄÿÄÿÄÿÄÿÇÿÇÿÇÿÅÿÂÿÃÿÃÿÂÿÀÿ¾ÿÁÿÀÿ¿ÿ¼ÿ¿ÿÀÿ»ÿ½ÿÀÿ½ÿ¼ÿÂÿÅÿÃÿÀÿ¿ÿ¼ÿÀÿÀÿÁÿ½ÿºÿºÿºÿ¼ÿ½ÿ½ÿºÿ¹ÿ»ÿ»ÿ¾ÿ¼ÿ¹ÿµÿ¹ÿ·ÿ¼ÿÀÿÀÿ¿ÿºÿºÿ¹ÿ·ÿ´ÿ¶ÿ¶ÿ¶ÿµÿ¶ÿ´ÿ¹ÿ·ÿ¸ÿ¶ÿµÿ³ÿ±ÿ°ÿ±ÿ¶ÿ³ÿ´ÿ³ÿ°ÿ²ÿ²ÿ®ÿ±ÿ°ÿ®ÿ®ÿ¬ÿ®ÿ®ÿ²ÿ²ÿ³ÿ²ÿ³ÿ³ÿ²ÿ°ÿ±ÿ²ÿµÿ´ÿµÿ´ÿµÿ²ÿ°ÿ°ÿ®ÿ°ÿ³ÿ°ÿ°ÿ­ÿ¬ÿªÿ­ÿ«ÿ¬ÿ­ÿ°ÿ®ÿªÿ«ÿ®ÿ¬ÿ¯ÿ­ÿ¬ÿ«ÿ¬ÿ¬ÿ¬ÿ©ÿªÿ©ÿªÿ­ÿªÿ­ÿ¬ÿ©ÿ«ÿ«ÿ§ÿ§ÿ¥ÿ­ÿ®ÿ°ÿ­ÿ«ÿ§ÿ¨ÿ©ÿ¦ÿ§ÿ¨ÿ«ÿªÿªÿ«ÿ¬ÿªÿ©ÿ«ÿ¦ÿ¨ÿ¨ÿ§ÿ©ÿªÿ¬ÿ¬ÿ°ÿ°ÿ«ÿªÿ¬ÿ­ÿ«ÿªÿ¬ÿ«ÿ¬ÿªÿ«ÿ¨ÿ§ÿ¨ÿ¦ÿ¤ÿ©ÿªÿ§ÿªÿ¨ÿªÿ©ÿ©ÿ¬ÿ«ÿªÿ©ÿ¨ÿ¥ÿ§ÿ©ÿ©ÿªÿ¨ÿ£ÿ¥ÿ¤ÿ¢ÿ¦ÿ¥ÿ§ÿ£ÿ¡ÿ¢ÿ¥ÿ¦ÿ©ÿ¦ÿ¦ÿªÿ©ÿ©ÿªÿªÿªÿ­ÿ­ÿ­ÿ¬ÿ©ÿ©ÿ«ÿ­ÿ«ÿ¦ÿ§ÿ¨ÿ§ÿªÿ¯ÿ¯ÿ­ÿ«ÿ¨ÿ¥ÿ¥ÿ¥ÿ¦ÿ§ÿ¨ÿ¥ÿ¨ÿ«ÿ«ÿ©ÿ¦ÿ¥ÿ©ÿªÿ©ÿ«ÿ§ÿ©ÿ¬ÿ¬ÿªÿ¨ÿ§ÿªÿ©ÿ¨ÿ§ÿ¨ÿ¨ÿ§ÿ¤ÿ£ÿ£ÿ¥ÿ¦ÿ©ÿ¦ÿ¤ÿ¡ÿ¢ÿÿÿŸÿ¡ÿ£ÿ¤ÿ£ÿ¡ÿ¤ÿ¥ÿžÿžÿ ÿ¢ÿ¡ÿ¡ÿ§ÿ§ÿ©ÿ¨ÿ¬ÿ°ÿ«ÿ¬ÿªÿ£ÿ©ÿ­ÿ«ÿ©ÿ®ÿ²ÿ¯ÿ¬ÿ§ÿ£ÿ¤ÿ¤ÿ›ÿ—ÿ™ÿœÿ™ÿ—ÿšÿ—ÿ•ÿ•ÿ˜ÿ—ÿ”ÿšÿ˜ÿšÿ ÿ£ÿ¡ÿ¤ÿ¨ÿ«ÿªÿ­ÿ­ÿ¨ÿ¥ÿ£ÿ¤ÿ£ÿ£ÿ§ÿ¡ÿœÿœÿ™ÿ“ÿ‘ÿÿ‰ÿ‰ÿŠÿŽÿŒÿˆÿÿ‘ÿ‘ÿ“ÿ’ÿ‹ÿÿ—ÿ›ÿœÿ¤ÿ£ÿžÿžÿšÿ™ÿŸÿ¡ÿ ÿ¡ÿ ÿ ÿ¤ÿ¡ÿ£ÿ­ÿ£ÿšÿ“ÿ•ÿœÿ™ÿ£ÿ¦ÿ­ÿ±ÿ´ÿ¬ÿ¯ÿ³ÿµÿ°ÿ°ÿ¶ÿ²ÿ´ÿ·ÿ¼ÿ²ÿ¶ÿ³ÿ³ÿ²ÿ³ÿ±ÿ­ÿ¬ÿ°ÿ°ÿ©ÿ¨ÿ¤ÿšÿ˜ÿ—ÿ–ÿ–ÿœÿ™ÿ‘ÿ–ÿÿ¤ÿ¢ÿ¨ÿªÿªÿ¡ÿ¥ÿ£ÿ¡ÿŸÿ£ÿ¤ÿ£ÿªÿ¥ÿ¡ÿ§ÿªÿ¯ÿ®ÿ²ÿ·ÿ¯ÿ¨ÿ¢ÿªÿ®ÿ¯ÿ­ÿ±ÿ¸ÿ³ÿ²ÿ°ÿ³ÿ³ÿ®ÿ¯ÿµÿ´ÿ³ÿ±ÿ»ÿºÿ»ÿ¹ÿ²ÿ±ÿ³ÿ²ÿ²ÿ²ÿ´ÿµÿ¸ÿ¾ÿ¿ÿ¿ÿ·ÿµÿ·ÿ¸ÿ½ÿÀÿÊÿÍÿÌÿÐÿÐÿÍÿÍÿÏÿÌÿÒÿÒÿÕÿ×ÿÛÿÛÿÕÿÑÿÓÿÒÿÖÿÙÿÙÿØÿÑÿËÿÐÿÔÿÚÿÔÿÓÿÕÿÞÿáÿÜÿÝÿÜÿØÿÛÿØÿÖÿÓÿÕÿÔÿÏÿÏÿÎÿÔÿÕÿÞÿàÿàÿãÿâÿâÿäÿäÿäÿàÿßÿÝÿÞÿèÿêÿðÿðÿíÿïÿòÿóÿôÿðÿðÿéÿæÿçÿãÿàÿâÿßÿâÿàÿáÿÝÿÚÿÙÿÛÿÙÿâÿàÿàÿäÿÜÿÚÿÛÿØÿÝÿÞÿäÿáÿÞÿãÿêÿëÿñÿóÿîÿìÿçÿáÿæÿäÿìÿéÿéÿæÿëÿíÿèÿåÿäÿåÿìÿéÿéÿñÿîÿïÿôÿúÿýÿúÿüÿÿÿ   ýÿöÿòÿîÿïÿõÿîÿêÿêÿêÿâÿÛÿÚÿ×ÿÚÿÙÿáÿãÿèÿíÿ÷ÿúÿüÿüÿÿÿ  ÿÿýÿúÿùÿöÿúÿüÿùÿóÿíÿíÿóÿûÿöÿõÿõÿûÿ  ÿÿÿÿÿÿ          "!#%)+& !&$%-60*("# )+(.4.-0,# #'&%! &).::;ABFMFDCABD9>DACC;>C??9;<;>=?;:?>=7;CAEE@C@B?96<?9BCF><;5548<DEE=<DPPKQMTJIPVY[_[UQJGJKLFBADDFFHDCJIDA>>@@959CAFKEHIACKPKGHDBDIMGGILMKI@CGCBA@=ABHABHHFDLNIMKNSY]^[_^dhedcb_`aZ^``^\XWYYZWXYZWVSQPU[POSTVUUZWSNMJPOOGHLNRTTOPROX]]^XUURKMLOORROOMNQOQUY[^`ddcba`[[ZQTWXSQNKKLIDIFHJILLSMQUPMTWPTYTQUMJLOMLPKLKGJA><9<BGHPPJIIFHJJGJMMQNKLJD><::>ABAACD==9879786128<9>:7;>:>ADGGHIJC@<<68<944411/.,*+1250,,+--05789:?A:60**)+.+++$$&(! #! !"#"! $'(&+/3--*%"%#%" !!' $"$)&&%$%%"     üÿÿÿûÿüÿþÿøÿðÿóÿ÷ÿöÿ÷ÿôÿöÿôÿóÿñÿñÿòÿîÿòÿóÿ÷ÿûÿûÿúÿýÿùÿúÿüÿüÿþÿüÿúÿùÿõÿòÿïÿðÿõÿõÿóÿìÿíÿíÿðÿñÿñÿôÿ÷ÿöÿñÿïÿóÿúÿýÿþÿûÿ÷ÿøÿøÿûÿþÿûÿ÷ÿøÿúÿøÿõÿöÿ÷ÿöÿóÿîÿòÿïÿëÿðÿòÿñÿêÿîÿðÿñÿòÿôÿðÿëÿéÿíÿëÿæÿæÿãÿãÿåÿàÿÜÿÛÿßÿßÿáÿâÿáÿÝÿãÿåÿæÿãÿåÿëÿéÿïÿïÿêÿíÿñÿòÿíÿðÿïÿíÿïÿïÿëÿæÿéÿêÿåÿèÿéÿèÿæÿçÿäÿâÿâÿæÿçÿèÿèÿäÿâÿãÿæÿêÿèÿíÿðÿïÿñÿùÿòÿñÿéÿêÿëÿòÿòÿîÿðÿìÿèÿçÿãÿÛÿÚÿÞÿÛÿÔÿÍÿÒÿÞÿàÿåÿÛÿÒÿÖÿÞÿàÿÙÿåÿäÿØÿØÿÜÿàÿãÿëÿæÿàÿåÿæÿÝÿàÿèÿßÿÜÿèÿìÿãÿãÿäÿáÿÝÿáÿàÿáÿäÿëÿæÿâÿàÿçÿìÿðÿíÿìÿèÿïÿðÿðÿöÿöÿôÿíÿëÿêÿêÿïÿìÿëÿåÿíÿïÿëÿòÿôÿôÿñÿçÿêÿìÿôÿóÿèÿïÿñÿòÿôÿðÿïÿíÿîÿðÿìÿòÿéÿãÿäÿæÿäÿçÿéÿìÿëÿéÿíÿêÿçÿìÿêÿâÿçÿêÿçÿèÿðÿïÿïÿñÿòÿóÿîÿðÿñÿëÿïÿòÿóÿöÿöÿöÿöÿíÿðÿðÿïÿóÿðÿóÿöÿùÿüÿþÿþÿþÿýÿýÿþÿüÿ÷ÿöÿöÿùÿþÿÿÿüÿ÷ÿôÿðÿïÿñÿóÿóÿõÿôÿõÿîÿîÿðÿïÿôÿòÿðÿìÿòÿ÷ÿûÿþÿúÿþÿýÿùÿûÿúÿúÿôÿúÿøÿûÿøÿüÿúÿûÿ÷ÿõÿðÿòÿïÿïÿñÿòÿõÿøÿøÿüÿøÿüÿûÿüÿüÿþÿýÿýÿÿÿüÿøÿøÿùÿüÿüÿûÿõÿøÿùÿûÿøÿøÿþÿüÿúÿýÿþÿýÿüÿûÿÿÿþÿûÿûÿýÿÿÿÿÿýÿùÿüÿøÿûÿ÷ÿòÿñÿîÿôÿóÿíÿîÿîÿîÿïÿìÿïÿôÿôÿ÷ÿ÷ÿôÿòÿóÿòÿôÿõÿöÿôÿóÿ÷ÿùÿöÿ÷ÿôÿôÿõÿöÿ÷ÿôÿôÿõÿùÿ÷ÿûÿ÷ÿõÿ÷ÿùÿòÿñÿôÿóÿñÿóÿöÿóÿòÿñÿðÿéÿèÿìÿåÿêÿéÿêÿêÿêÿîÿíÿëÿçÿìÿìÿéÿïÿïÿìÿìÿèÿéÿîÿéÿéÿæÿßÿáÿÝÿÛÿÝÿÜÿÝÿßÿÝÿÙÿÓÿ×ÿÛÿÜÿÝÿÜÿÝÿÝÿßÿãÿßÿßÿáÿåÿåÿæÿéÿîÿìÿéÿéÿéÿêÿèÿæÿàÿàÿàÿÛÿÚÿÙÿØÿØÿÜÿßÿÞÿßÿÜÿÛÿÚÿ×ÿØÿÙÿÛÿÜÿÜÿØÿÛÿÙÿØÿÙÿÜÿÜÿÞÿÜÿÞÿÜÿÚÿÕÿÕÿÔÿÒÿÐÿÔÿÔÿÔÿÐÿÌÿÏÿÉÿÉÿÌÿÎÿÌÿÌÿÇÿÆÿÆÿÈÿÎÿÍÿÉÿÈÿÈÿÉÿÇÿÊÿÉÿÃÿÄÿÀÿÄÿÃÿ½ÿ»ÿ¸ÿ¼ÿ½ÿ½ÿºÿ¹ÿ»ÿ¹ÿ¸ÿ¼ÿ¾ÿ¿ÿ¼ÿ½ÿ¸ÿºÿ½ÿ¾ÿ¼ÿ»ÿµÿ·ÿ¸ÿ¹ÿ¶ÿ´ÿºÿÀÿ¼ÿ¹ÿ¼ÿºÿºÿ·ÿ¶ÿ·ÿ´ÿ´ÿ´ÿ³ÿºÿ¼ÿ¸ÿ¹ÿ·ÿ·ÿ»ÿ¹ÿ¶ÿ²ÿ´ÿ¸ÿ³ÿ³ÿ³ÿ±ÿ²ÿ²ÿ¯ÿ¬ÿ¯ÿ®ÿ±ÿ³ÿ¶ÿµÿ¶ÿ±ÿ²ÿ²ÿ²ÿ±ÿ²ÿµÿºÿ´ÿµÿµÿµÿ±ÿ¶ÿ°ÿ­ÿ¯ÿ±ÿ­ÿ¯ÿ³ÿ³ÿ°ÿ¯ÿ¯ÿ¯ÿ±ÿ³ÿ±ÿ³ÿ³ÿ³ÿ´ÿ°ÿ±ÿ¸ÿµÿµÿ´ÿ³ÿ±ÿ±ÿ³ÿ³ÿ³ÿ´ÿºÿ¹ÿ´ÿµÿ³ÿ°ÿ°ÿ³ÿ¯ÿ®ÿ¯ÿ³ÿµÿ¹ÿ¶ÿ¶ÿ¸ÿ½ÿºÿ½ÿºÿ¾ÿÀÿ¾ÿ¾ÿÁÿÃÿ¿ÿ¿ÿÁÿÃÿÂÿÅÿÄÿÈÿÊÿÊÿÉÿÌÿÌÿÉÿÌÿÈÿÆÿÉÿÉÿÈÿÊÿÎÿÈÿËÿÎÿÑÿÕÿØÿÖÿÑÿÔÿÙÿÙÿÕÿ×ÿÙÿÚÿÝÿÞÿßÿàÿÞÿßÿÝÿÛÿÚÿÜÿàÿàÿÞÿáÿçÿæÿäÿèÿêÿëÿêÿèÿèÿèÿçÿêÿðÿíÿèÿíÿðÿ÷ÿ÷ÿóÿõÿøÿøÿøÿùÿýÿýÿ÷ÿýÿýÿýÿþÿùÿ÷ÿ÷ÿúÿÿÿüÿþÿþÿþÿùÿ÷ÿùÿùÿüÿÿÿýÿ    !# #'! %$%'+))+--()$#$&"%"%''"""$%-22653121012676422333561*++)),100/+)' FC!.S"IS0Iðÿóÿ>!ºÿ´ÿK~Î$¥ß:ŠtÀN$Éþ%ÿÆýŠüåú ù øÈ÷øúîûbýäý}ý0ü©ú6ùçøÇùfûÛý—ÿzÿlþ!ýxûÞùøŒ÷÷-÷ŸøâúýÎþ!ÿõý½ûYùøbøgútýtìÒC<— Á@W gòõÿÔÿD¨]¯¹UúqíÏÛN' 5 ƒ à Ø W § \TÂuS´Õ›1­ ÿÇüËú¥ù)ùsùÁúÂüÚþ”•º ÿ?ýúFø¹öö/ö¿öA÷I÷…öCõïóóÝòió7ôøôøõ1÷6øùúû6ü¶ý”ÿcÁnhÒñ¨Ïn‰°£’og{Oÿþ ý'ü‡ûDûUû¼ûüËý)ÿ}£c­“Y@B^xy5›½¯ÿ–þuý£ü\ü™üQýFþJÿ;(íĦœ£_uËoŒœüÿ¬þÞýcýkýØý˜þŽÿvNõKgu¿VËvȼÁòfÍò€J^¶.“³tû6LP.ÿ3þ·ý”ý©ýøýAþBþþÅýµýÔýDþ÷þ¢ÿ%tS®ÿ¤þbýüûRú?úíú!ü˜ýÁþ|ÿŸÿxÿuÿ ÿ¨@ÚTPì1@‚ÿÿÿ‡ÿèÿñÿ‡ÿ§þýíû-ú’øÈ÷6ø¨ù´ûÈý}ÿOkU?YÔ«­žäz”ƒ™ýÿ×ÿ˜5á~ÿ±(aòÿìÿžÂس¤­ÿÍýTü‡ûUûOûRûŽû@üýÌýDþHþ þÚýËýþ6ÿÁ;t:Zá݇,nÿQÿpÿ€ÿëÿÀà’g¸\“KÁBߦZò!Üb¦ÿþýŽü“üýþÝÿWÍ£V¨· ÿ÷ü±ûbûëû ýVþ[ÿ¶ÿ9ÿdþ‰ýýCýÿý9ÿà«[To¡C–Üÿbþuý7ý^ý°ý þHþCþÞýDý®ü<üüoüÜüûüýÙüüûùùÛøBø%ø˜ø~ùèúçü8ÿh+¤XXú-Ÿä‡fF¬1æüúü÷höÅõ‹ö‰øhû±þ¢[è(VŒÿzþ–þšÿIÄ ï±~ÿ‚þjýæûbú4ù ùúüÀþ:ÐP.ó6Ò›ú›“+À ÿÊþZþèý¸ý®ý®ýäýŸþOÿÞÿ¡#?§Áÿ®þ%þþþ•þ5ÿèÿu‚’úª€ªÍ´Al½>­)/ ‚ * ‡ ƒÕ3=Zc¡³ Wþ'ünú¥ùÖù%û|ý¥ø¤IAZÿTú öBó€ò•óÖõ†øÔú,ü¶üUü}û¢úgúÿúCüëý¦ÿdÛÞci®Fÿºüõú„ú û{ü–þŽÒ2¶ÛkMvÿ†þýûÀùKøx÷=÷–÷qø”ùÈú,üÇýAÿ*p9›ÿ³þ²ýúüÆüLý¤þˆ™ÎüZ{þ|üžûüÓý‡¬e9ûÝëÿCþ\ýýgý þÛþ¼ÿ§©‡Y.·3朓wà“¤8Â…ÿpþyý¾ü+ü_û$ûàûcý¤ÿCJ| A Q Œ æ i 1^ƦÃþ*ýü3û?ú ù˜÷"öõõ0öï÷Ôù™ûwüyü+üü¿ü/þ^`h;þÄý[ûùQ÷)öôõêöÁøÏú‹üVý'ýWü|û6ûôûýðÿD3Yž*­Ì¥þéýÔýûýþ/ÿ»ÿ<´\ þwÍÈØrÐJÕ9͘i}Z¢ˆ_ÃÛ;û˜‹øþ„ý„üëûãûQüòü‡ý1þÿþÊÿ¥·çÚˆÏ`Óûý û{øâö¦ö_÷ ø¤ùïùyù˜øÂ÷H÷†÷‡øúûý1þ ÿÇÿ|+ËJ1‡œ¿ÿIÿ<ÿûÿ{zšbm¤1´nýÿ;ÿ±þ÷ýý|ûÕùyø¤÷À÷Êø£úÌüîþÁ&'ìu´“û*!æ±ÿAþÍü–ûÔúÃúeûüåý7ÿAµÅÂáMÛoЧU™ ÿOÿßþþ2þþþlþÿÇÿRX§PyR U i K RÀNe!ÿIþ®ýEý»üêûÞú·ùíø·ø ùÐù$ûü¶ýŽþþþ'ÿ”ÿ*&FéêM þ%üú7ù´ø»ø:ù2ú{û¤üiý„ýý,ü%û‚úVú³úAû¼û9üüØü@ýÂýÙþuQ$}š¼»ë¸bƒª™¯ ÇŒ7­ÿ å z"Û3èûzÌ\Oø¦€¨K†tËûûkvtþ€ü×úÉù¿ùÏúÌüÿëž„ûýXú‹öHó ñ'ð†ðøñôzöÑøåúoü]ýâýþþ·ýDýýÎü¸ü¾ü&ýîýáþîÿÒ^ƒC¹dV¼KÃ Ä èé>Ï£ÿñýý^ýŸþ޳«6p#)¬ÿÍþ¯þÿªÿ€ÿaþôüaûÕùžøÄ÷g÷®÷Šøçù´ûßý°ÅÔùŠäŒÿ­þHþRþ¥þÿfÿÞÿ0*§ÿÊþïýOý+ý~ýWþ·ÿr>%]ÄpAŸþÛû3ù1÷¨öç÷búÍý;÷îïnÇK)I¹œ€ \‚ºþ»ü üzüêýwÿ•¶²ÿØþeþLþ£þéþ ÿýþ¼þIþ²ýòüÚûŽúPù:øý÷‡øúýûfýçýDýñûëúvú°úŒûºüÜýµþ7ÿ¡ÿáÿ ëÿÕÿºÿ€ÿ!ÿßþ5ÿ3–¼´´ C ÷ ” Ñ ÛWÞÿ9ý³ûeû>ü«ýÿ*­Þ5ÒˆO`z€ƒ ´nÿÆÿþRýbýþ<ÿ§\úÔO°;Ý`˜•ÿwþ7ýüû(úŠùXù•ùeúüþÛ52tgþ«ü û&ûûû-û‹ûüü¿üžüüöü þ©ÿØB‘T\ Üõ=>kþ$üpúLùÛø2ùmúêûýŸý„ýÃü´ûáúËúîû0þâMªŸ‰þ#üûôúPû[ü.þ¨t1C~ Ñ d y;Ó›˜ñšùÔÿÎü¿ú6ù‹øTømøªø ùúŠûTýòþ0òòazÿÙþÍþPÿ+Ë=ch©*ø~< ª m ] „ , ªÁxhÈÿÄþƒþ!ÿWÆŽ*¥ÿ>+ÿüýýÄüÒüý8ýøüðû{úoùù©ùÖúüçü“ý+þpþ:þÀý#ýcü˜ûãú‘úÛúÉûõüþÞþ_ÿ& -tï4îdÇtlÿÅû@øãõÉôÃôöõë÷Žúœý‘—aÜP’ÿíýý7ýWþ♲% žàÖY!½ä† ò A C Ç t+@(“ýåû_ûîûAýìþŸ)fÄŽ mþýÍû¬ú¯ùíø.øf÷Óö¶ö ÷øiùóúéüHÿág’3m ? ™ H 6 C‚Qþ*ûçøœ÷Q÷Ñ÷åølúSürþ€öÆÉ>1ðÿœþcý"üLû±úšú¸úRûüÚüæýUÿ"C¨3    ƒ d Œ´åSþ ü‡úyùÍøäø€ù®úVüÜýÿ×ÿ“4êâ§Årð·þûûxùk÷öäõµöJø[úlüYþvÿ&Jÿÿfÿãþ”þÿÅÿ*`i÷ÿTÿjþNýýæý>ªZ ƒ î Ó^ÌÿÄý–ü üéû üŸüWýAþíþÚþ3þ"ýnüý$ÿQëÎA  Æ%Âëw ¦ Ú u  é ® òÝÝþaýŽüðûšûŒû6ûíúëúìú&ûÕû‰üiýtþ«ÿy㦰ÿÿýþû¥ùu÷Áõðô&õ•ö ùÉû¾þ§æ se ¦=©·ªÿýü3ûbûyüðý³ÿªf”Îëþ‡ÿ´üæù¨÷öEõõ_õíõXöƒöMöòõôõ³öHø úßýq½K à € (ÇȈÿ­üÕú*ú¿úAüþQÿ6ðüuRigM—Rû°þŸüçúˆùÇøÆøyùåúëüÿ ¯äÝTÄÝ R   T::!ùþ.ýÑû>ûqûKüâý#¡? @ .Øì ¡ v9»ý¼ûxûü.ýþÔþÿêþ@þzýýLý£þ¥¹†=0¦‚þVûGøžõwó8òûñ)ósõ,øœú‚ü«ý(þxþ´þ0ÿfˆ)±“ÿ'ý%û¿ùäø›øùTúHü³þùSN?Ãÿ†þ-þÖþÓÿ¬iîÐT z{ë—(µR¼&¿,ýEú¨øWøTùzûxþÛ7)à ù ™&:`"þýãü0ýàýœþóþ¤þþuý'ý<ýâý2ÿ!†A G l  g «X´_ý ûþù@ú•û®ýèÿ‘Y0]!ÔþÜýDýÀüøû½úúø¿öpôœòÃñòMóõG÷‚ù£û¥ýtÿÙ–Z„v š Ç«†ÿ`ý¿ûÐúÃú¢ûTý·ÿoJç° À - øR^(ÜÿÅý üûÀúûìû1ý¤þ,ÍD¥AMÊ”±(þWûjøµõtó°ñBðïðúñ õåøòüÖlýÊ G š ¼ † | ·›Trìÿÿšþ?þ*þ¡þgÿÁ’ˆþ„ëÕ@Vñÿ—þ#ý€û%ù÷/öö*øåúÜý„nQ‡œ­ê10ûKÿÖüÏúøø}÷¢ö‰ö®÷®ù(üþþwÿ‚8cŽÝu>Qò#•ÙžÿùöúUGåùkþŠû ù”÷÷ø3úý€¬óY­0#áÃâ ‚Ð-A|3ÿÓþ ÿGDˆÆÇ< æ9åXþûnøÅöEö÷œø‹úbüÛý¨þâþsþrý0üÚú€ù=ø÷ö9õŠô ôØóüó\ôÛôbõïõÃöò÷ˆù£ûMþg±×y # l oÚsý˜úÃøøDø?ù×úýªÿm6ǯ Ó \ GÉÿXÿþ6ýýÉýÿx‘q–} - ¼t=‘ÚÿíüúÒ÷ÑõÞóÂñÝïÎî ïÀðÝóÓ÷Iüîè^’¶A°ñÜeœ³ÿ²þ—ýØüGüæû*üý*ÿS%Ù Ä kdà æ Öç!=þÑûú¼ù”ú8üZþ? gRÿ³þÓþŽÿ¤¬ÜgÿŽýGü]û–úøùäùˆú$üZþ”WgX^%°ÿüÿæó¶gŒöÈSÙ9vJ`„ýØù-ö"ó%ñüðñòUöúÐþj¹œEÓÙõÿ‡þåýñýtþÿ‰ÿ³ÿØÿ[XM¦X`·Z)Y ‘ & ® á ® sèošýÉû-ûÎûAýÛþ–X¥ÿ›þhý>ü9û=úù÷µõ ówñ³ïÛîîîÁï2ñ ó9õ±÷\úý®ÿEï¤ ð Ì n Ð *Á(äýZû¹ùëøÃø9ùQú#ülþ°®C;Ôó©Û’î:Þþ×ýý³ü¾üký‡þºvd‰¶ ‡ ì Ò ×  & Â7UŽü€ùÎöô¼ñ‰ðûð$óÅöpûÊsö¢ Ü ý F=û9HbÿSþýÌüZüÛûYû7ûÊû{ý‚•s`ŽÎ °ý û‡ø~öpõ<ö;øêúÙý3šÂ;Wšÿ¼ÿˆ˜ô”/[þŽüÇúaù3ø¡÷Á÷ªøhúýhÿû¿8¿ eÓò± cª û1œ:ó”°õÓl]ýoùöüô?õ[÷²úÊþÙ$7Õi·“ÿMþµýÆý/þþ®þ«þŽþ?þ'þvþÿöÿæ‹Šá › ò é ÄÚeÿ"ü<úªùAú¦ûzý<ÿTmæÿ5ÿ¶þXþßý)ýøûúª÷õ½òñƒðñUò9ôröÔø:ûyýIÿ¥çe.–’ ¦ ¨¹0jµþpüÈú ùùÿø¿ùQûŒý§½¥ÓØ^v{zÿìý»ü‘ûÜúŸúûü ýºÿô?d÷îP  á ãâÿˆý;ûJùo÷iõpó]ò§òrôñ÷Tüe4¡ h ¸ 5 × ?m)/9pn†Æÿ‚ÿûþÍþÈþiÿCãÁŸÐg[%ÿØûÈøFöèô2õ ÷ÜùKýx¸ÄD:8ßA¢€_{þüÀùè÷`ö7õõ¥õ÷ØøJû±ýÿÜÿ%?o(4tf&Õ<—ÁÑ·»¯É‡Ù}šªÍPþû¸øž÷Ä÷’ùƒüüÿ–òm x j Ë0òÇÕù1Okÿ°þNþnþ_ÿŽ•:ΙÓr廦‹êåÿýÓúMùÇø?ù*úû§û±û"û)úCù¾øÉøùïøZøóöÞô©òñuð†ðúðŠñEòFó•ôOözøûú ýi]C§E û  «Ø'åþýÛû,ûâúûãûý­þ’¡ŸE€&#Ž|%Ú˜o†½ÿöþ2þ¢ý¥ý›þ7/T1ÉÐ ˆr5r¨×1ÿÃý-ü›ú#ùü÷÷}ö‘öÝ÷ÝúÝþÛ‚1 Þ  Ô oó2Q“þU$²õ/|ÿÿšÿv\ÁU  > Vô ü\÷úóúò‚ô‹÷,ûžþâÆ;ãÿÉþBþ~þ$ÿI¼ÿ#þ·ûQù÷"õ°óó¹ôm÷­úVý!ÿÚÿ!ÿ‰ýüSû¤ûý"ÿ,w:p$ITyT)t¨rh/ýüÿØü<úoøÓ÷nøíùëû þÒ°[+ & —º–wèž²ÊÙáÞ†0³‘ÿ <<j©.V7)¦þ™ýýCý¾ý'þ^þ^þ0þ¤ýÞü+üÅûû2û1úiøôõ*ó­ðîî;îvî^ï¼ðnò3ôèõ±÷¿ùüŠþ%͸r5:¶ÖÄ¿ÿÝýPü[ûû‚û¥ü@þ¶3\oG¦º¯»ÿŽJÎÿFÿþÿý¥ýÀýiþ¢ÿ"€{â¤éÍ~Vÿ€þ þúýþþþþÃý€ýjý›ýŒþ@To&:“ÅñC¼_\e–ÜçòJÒ&deAbþøÿ±ý‘ûòù½ø.øEøÝøÈùŒú3ûçûÈü÷ý)ÿïÿÖÿÿüý¤üðúyùø÷çö±÷cù¹û)þÿÿÄ#þ´ü û6úúTú‘úû¹ûWüý¿ý{þcÿZB.NYp<î?\rÔˆ¾H±ý3Sv¯¾„Y$ªåêŠÆÍš´[B}µ¹‹GÞ-;¢¨ÿ´þ`þqþÄþFÿœÿÿÚþ®ý üwúù:øøkøáøùÁøÄ÷7ö_ôòJñ¥ð³ð_ñbòTó ô³ônõtöë÷Ôùõûþ¡ ²@ÅJðë@Ïg´­`öŽL*0%ÕBªÿ;ÿ ÿ&ÿyÿÑÿ a†¡Àó,[Pñ8?ÿIþtýãü¢ü¯üý¨ýbþ?ÿÆ<„Ãô;£ J@Õ#=ßäw=)Hm[5Í”s–k:Ê3‡IèÿÂþ8þ6þxþ“þ~þFþÅýýüWûxûAügýdþúþâþ-þêüGû´ùGøV÷÷Ñø!ûãý–¦ƒ#¹”ÿ|ýïûúúœú‹ú¢úîúYûûüûIü½üaý>þ!ÿ ´Hƒ€C§òÿÿjþIþÃþÃÿàÒƒì4\¢Ä§9xMÉl³“®Ì‹Ð£%K¬?ƈÿuþÇý“ýÝýzþ5ÿºÿ–ÿÁþsýüÈúüùÇùúÇúiûžû<û2úžøÉöõÄóüò·òóÊóÈôÀõ¡öƒ÷ø³ùûfüÂýûþõÿª èËÍü[ò¦f!¯åºUÛD¢n˰›—‘žºØ N§òBQR>ÿÿÂþ·ýý²üÄü"ýÔýÉþÙÿßÄwÏï÷ìêÍ‹ü=Œÿÿ¸ÿÿ©ÿ.3HGW:Ì!†M”= m—ÿkþÑý‰ý¹ý-þnþ þŠþÝýÖü™ûƒúÐù¯ùÚùšúoûñû;üGü0üñûTûú#úbúPûÐü¡þ^‡Èf–Ïÿ9ÿúþÿ.ÿÿÿÿÿ*ÿQÿtÿÍÿ8½XöOMÊÿ!eÿ§þþêý>þ÷þ7o‡NÃø !8S}lðiË<à'ü$qhÎûíŒëóï_îÿÉþþ|ýMýuýñývþÏþÆþVþ~ý\ü@ûcúëùÝùú0ú-úÕùù5ø[÷–öñõ‹õœõöòöÏ÷¨øŒùpúoûšüÎýÎþÿ/Â0·Þ ý bõ‘ëè”ìJ‹½ÿóþ7þžý;ý ýýý+ý(ýý(ýˆýLþDÿ1êDCö€”ÿOÿJÿlÿŒÿ ÿÓÿ(†åHe} çFwwÿHϤ¹ñ0ÌVH!Ì@w2ÁOº"¢œïp Dÿ|þþþ þpÿ2†PáÿÑþ‹ý.üû”ú­úrûúûrü€ü&ü»ûVû/û2ûpû×ûŽüèýdÿ°#ºÅÿ¶þðýšýÐýVþÿ†ÿ¸4’ÏŒEÏ÷õ•ÒàM¢ïÿ•ÿYÿjÿ ÿÞÿVÊ‘žÕüþ Îp”‘l ñ”ö]gþ)ÒY†lé@äþ¾ýÊü-üéûîû#ü€üÓüÏü>üûÎù•øœ÷ùö¨ö¯öæö÷%÷õö¯öPö öäõ÷õRöæö·÷´ø¸ùªú¬ûÚüTþúÿêó¡êݸŒvw’³Ýq³¨L°ïK¸fWab<ï˜6»ÿ;ÿÓþuþ?þ5þUþ˜þ÷þJÿ‡ÿ–ÿ_ÿäþ9þxýÑüeü@ü_üØü¦ý‘þ¤ÿÊ»yå:{¬¾fÒòpÿÛ¼ÙS:syãL©ô×–íÿ?ÿ€þÒýjýkýþcÿ³„ÁîÞÿÜþ¿ýÒüü±ü×ü¶üDü‹ûâú5ú´ùnù{ù#újûUý~ÿd~ˆÆž€ÿªþ<þþþýÿýJþuþsþ=þþ@þÿSïˆ ‚.`x³3í;šY'è“‘è¥hÆèeZÒÚ~2’ªÓ¦$^Yyhá=ξÿàþ+þ³ýyý†ýÌýþ1þÈýÉüOûÒù€ø…÷ôö©ö~öJöíõAõkôšó óøònóbô‡õÝöCø˜ù¯úŠûGü,ý`þœÿ° W¼ÝÕ®zODhºBë•üþŸÿ6på‰UKNIGI5Í|(Ýÿ¨ÿ—ÿÉÿ'½—cÿ¢þôý‡ýyý¼ýþþÿ—ÿ »x;ó©nˆþÞ²ËÝK+al¬!ˆ¨TŸt¸½o²5øÿÜþ›ýSüdû!û£û“üÀý¬þÿ3~M¥ÿÓþYþNþyþpþXþïýý üõúÎùÊøCødøIùòúÄüþßÿrC”ÿ¹þþ¶ýÃýþgþ¢þÈþ±þIþâý¦ýÁýaþOÿµ=”޿ހ ­Bçëî V¦R-Ìw©RÅßø….Dot/­íçjUÛDÄ[ÿûýRý ýýtýÛýþÙýýúûŸúQùTøð÷ÿ÷>øgøHø©÷¥örõSôkóÚòÁòcó²ôqöIøú›ûìüþ&ÿ/ î§$CÊf÷‘B+u¹ÝÔ“3ÓˆQFOiެ¢cïM{ÿ®þþ¤ýœýîýtþþþiÿ©ÿ¥ÿmÿÿŽþ!þëýÐýÂýÈýüý;þžþÿ²ÿ4Ì‹yu7“w ¬Võz˜&ÂS²×ÔR®÷íi§þ7ýoüYüÐüDýëý`þþvþàýýGü6üÌüÇý¶þNÿoÿØþúýðüºûÉú:úFúèúåû÷üÙý9þþrý¿üZütüýþÿ¿ÿÚÿ–ÿØþãý%ýý˜ý«þ+À9=§P˜ÅaZ¼cå# ŠÊ4ù¶ï]òk‰ ì • ‡zå¿)CùÔ† <O‡±–8KÙ?ÿ¯ýAüûkúúúúêù`ù’ø‰÷…ößõÐõMö-÷ ø’ø‹øó÷÷öGõ©ôNôWôÅô~õ]öX÷aøžùûÅü¤þ‘e+ºÉ—Lû¼ŒfZXG~­²ÝMSÜ#©üÏ`»÷0~ÿóþ™þpþ`þGþþÚý°ýýµýöýlþãþGÿ„ÿ’ÿfÿ ÿËþ¤þµþ3ÿÿÿõÚbmp{ŠbC0OµYÔiM¾C³H»¼q; ÿ/þ%þ»þ‚ÿOÆ®;3ÿ‰ýþû ûÜúû¬üÁý~þƒþõý[ýªüóûxû7û|ûuüºýâþžÿ¥ÿÛþ•ý<üSû!ûÂûÜüþ¾þ*ÿ>ÿÔþ)þ¾ýÒýAþ ÿ:qŽö…²×¸åˆ@íDç?³.Òî¾´ºÅk W ž *  ±U+¢¤S>oXóBe‰Éÿ%ÿµþkþFþ%þñý‹ýÅülûœùu÷Lõó|òKòìòô>õLö ÷c÷i÷P÷÷¤ö?öõõÿõgö÷øùúVû»üþnÿ¤À¥LÒkÐi±§ZèGˆ¥‰M ÿ~þþ(ÿ$iÅ%Ú—¸ˆC-cáÿ¬ÿ„ÿ)ÿŽþÅýýücü)ü`üýüçýÿÌoá9l†…hqSé׌Y9”HÜæ-ŒD›ãE$†þµüHûÑúbûüþAÿ+oÜþ†ý6üfû4ûmûÈû'üIüü®û$ûÆú´ú¦úèú³ûýqþ¨ÿ8%—ÿÉþ(þÕýîý}þ@ÿéÿ§ ´B VÓ <ëq˜dçc6 ?êØç ÿ8}ÞŠh±XGhdHÄ ×„_šÆÅŒú$ðÁ‚ÿþaýüüâü,ýÞý¬þOÿ§ÿºÿAÿþUüTú]øöõôoó6ó;ófóšóïóXôÜôlõ÷õyöûö¡÷|øù¿úü>ýVþ?ÿýÿ‘ò2P\€á’zg0È*åcÉb޶Ô×qÍavJî~¥ul|¥®såÿÿ:þžýoý‹ýïý…þÿ|ÿ´ÿßÿóÿ4¬'ºgÖM…é!×K¬÷5©9Çõ|G ÕÈÚÌAÿÿºþÌýyý}ýóýiþÿ¤ÿÿÝþÈýÂü ü üÞüþçþ/ÿÍþýýýüðú úÁùZú¡ûLýÐþ ØóŽ›ÿŽÿ)µ?!»UìŒgxÁOÇî/·Yzüɤ9M©R¾† Ð¢“L¬sá%rm÷f“´¼’Kë??ïÿÌþÉýïü\ü"üüJürü_üÜûËúNù¤÷)öõ´ôæôˆõSöèö÷çöŸöHöïõ„õõÏôéôxõyöÙ÷ˆùUû)ýùþ­  –ŸVþºÐTÚn½Ã–LßU·“We¶>á~ýTc¸©‚}¶ÿGÿ6ÿMÿLÿÿ­þ1þÁý†ý˜ý÷ýþ9ÿ×ÿY™¡mT óÿåÿÙÞº¼Úd–V†z@¯íbÆ<Pÿxþ°ý6ýYý¶ý=þÄþmÿæÿÿtþ+ý9üùûpüýšý¥ý9ýyüÔûlûûûú$ûËûÛüþ ÿêÿF4ÔÿÎÿ“ .îuøÿ<¡'®)Æ€8—KoIL¹œô—Læ.'Ò^å{väÏ%†îÉñ•׮ʞ8¢ô=ÆjÌÿ+ÿîþÄþ¯þ¸þÿÿylÿáý¬û-ùÑö õ ô½óÿó~ôûôaõ³õ.öÔö÷ø÷øø!øTø•øù½ù¨úØû7ý›þÔÿÉyÓéã œžâ´Õˆò5^gW_‘ ÑÿóÿlþÿØn¬sÉÕÛˆ'Ã2Oÿ-þÿüüVû/û¡ûÀüBþéÿebâÞxìi-9E\sR ŠÂÿØÿOÓwˆ¹â(hY èà¯ê§ÿÄþ8þþþ“þÿ>ÿÿWþaýXüÜûíûªüÃý^þ-þeýsüžûìúú3ùÔø%ùú€ûæü!þ0ÿ8;@)+á#ÈòH­Kÿÿëÿ<ÙÜĶ ¡†¹-ø•&Ú8©]î ©¶ Z~€û°kTTGñlßRÕq»Q¯ÿ@ÿÿìþôþÿ\ÿâÿ„à˜…ÿÅý¨ûùØ÷’ö¶õYõbõ{õ‡õyõˆõ¾õöoö‡ögöAöMö®ö÷¹øHúüÓý³ÿuÄx˜DŸÿ±ÈNÝj™t$À]ëjíy ù(nÂ.ŸñáwçYüè^ž—DÀ_ÿ“þæý‰ý˜ýéý‹þDÿïÿiÖÿ=xÕPÈÿ¡=œ]ŸåC©Å¾”pg}t¨êû¾4j§ÿeÿNÿvÿÊÿ ýÿGÿîýKüõú^úŸú~û¡üóýÍþñþ{þÌýóü ü*ûkúCúÔúþû2ý#þ¶þøþ5ÿžÿKÃ@Q5ñ›1¿a:É•,®ÂÇ”?äoºyæ5A.EöGFîÒJ«<7W> ¢ûQÁ<â¯j.0ADIvÎ7²EïªþüZù÷põ’ô9ôNôªô<õÑõ[öúö”÷øUøIøøä÷Ò÷Û÷øªøŠù­ú ü†ýãþ îô_Ú‚O „¿›Xu~Š­ÿÿÖþÿ…ÿO,üšÃb—–›ÞŠÔ!9ôT¦ÿÿ®þ{þ¾þBÿóà|µ²]Ùmô D’f\`µe¿RNIù¤É´ÇxëÿaþüýÒýÇýïýþþ—ý­ü®ûöú û£û°üÍý}þþþmý¡ü˜ûúÃù ù+ú_ûü¾ýÚþËÿžeîy¦ôºoá_¸4Ø­ÎTò”ÚГnhÿˆ-šÒ¯5‚Š’û¯î¢£{ÓÆZÐb+ëͪ|)° gÛÿBÿ¯þjþXþWþ]þ™þÿÖÿɾy…™Çÿzý ûÁøøö¾õõ¯ô¾ôõgõ°õýõ]öÝö^÷Ö÷)ø€øÜøFùãù²ú´ûßü%þhÿogiKK•EYŒ¥ä¯ *ùdðÿlÎ7³;Á-dFÕ+t벿Ûð¶%VÿŠþëýˆý†ý÷ýÂþ¯ÿ¥zéÜ|#ϪŒ–Å÷Ó¢[00`‹Ð?™=C>Á¹©\Û+kÿÒþgþ0þ.þüýêýßý\ýeüûòùEùdùéùÒúüÐüý¶ü-üvûÈúúÕùúáú ü9ýXþUÿ(ÖmÝ8¡ú18ß™LãÐ× ’?³Æ pcu§!À]ÊÇg¶Î²ÞS!cõöá×}*Õ6¯9Õ]ÈJÞYÅÿ!ÿ¥þEþàý›ý³ý!þ¿þ„ÿ[ëò3²þ¿üœú”øóöìõbõ2õ>õfõˆõ„õ…õ£õÐõçõâõâõ öXöæöÆ÷÷øfúôûŒýÿ-µTq¦)ÛŸK®¦GœÅÕâdõÿÏÿz“|æ7_KïN¡ÃÀî(4éM¦ÿÿÀþ³þøþ…ÿEÍrÃØž]ùÎËÕÂ˱]ПÿjÿÏÿSîrÜ.WnS9õÓýð…„ÿÁýöüÁü¬üÎüNý¼ýÍý>ý.üûú_ú•úxûÄüËýNþâý4ýMüLûú6ùØø ùúLû‡ü¯ýËþÊÿ›J¾kɶUê‡V($b²*Á~je€GC:a™‰oðXÄ€±AÅñ”æEzÌV(úÕf: ­ÿ4ÿÉþXþþ¸ýœýÎýlþaÿXöÖâÿJþ[üKúbøÛöèõfõLõuõÇõöUööîö*÷B÷;÷&÷&÷V÷Â÷høTù‹ú ü«ý-ÿJö;A#Xþ¿þá„âÿæð-Àÿ ÿÊÿŒ°b¦íÊP³-æÜíöÍb¯ÞÿÿiþÝý×ý8þýþ)³òçÒ¥½¸Ö+‘ŒS¹!ôÿi´Á€UóL¸xûÿdÿ_þ3ýLüü$ü>üqü¹üýñücü/ûÞùÚø·øEùúüý%ý­üCü³ûðúðù"ùÜøNùcúKû(üýþÏþ ÿ@ Âï›{>/ObvÃVónzñZ÷ÔÄ.ð]$® ?Óã^c‚=VìÿŠ.îËŽ†z!ðÿ©ÿHÿÿ¡þFþÿý»ý‰ýŠý×ýeþÿ‚ÿ$ÿ!þ ü¿úÍø+÷öVõõ*õXõõ¦õóõaöÛö)÷-÷÷âöíö@÷ø(ù‰ú'üëýŠÿÏ¿:V3뤹4ë²\®¢h ó!>ˆ#H°(±GÑI¥ãÐqðb 2Q.¡ËïÿAÿÄþyþ†þáþ\ÿÅeé,$ùĶ΄ Ò-+Ì‘8¾Aö½“cî‘R…ŒÿJþ=ýšü_üSüüÙü©ýëýJýüTúßø&øSøùFúû\û6û¿úXúÐù#ù¨ø ø:ù‰úBüìýyÿ–;–³öv&¶Óº7”¦¦ä[1G^ïe½8ß½äˆBÊÉYÀÑýtCűñY¤B)‹›™ÒPùæ¾ZÃ&}àjõÿoÿÿ¹þ}þIþ5þ&þCþ¢þ#ÿvÿuÿÄþYýuû`ùG÷¡õžôCôkôèôbõ›õ«õÂõùõEö öÝö÷ö÷9÷•÷"øóøújûýªþ)_<ÁùúÉ·û{r„+™úP¯hßÿ“ÿŽÿÉÿ0¼1ŠïYÇ+a=Ñ@•µöüzÏÿSÿeÿ²ÿ:êŽ=Î@i2ØqPk’å$!¾%¡4úuË-@¬’}"Höÿ¾þëýpý÷ü™üªü³üeü«ûtú ùøà÷Rødùoú ûïúœúaú ú§ù&ù’øYøÄø¾ùéúüeýÒþ4aU(êf|dÊykr€‘ŽÐZ Ä á˜Œ¼í3¨öCDrÌ(Sõ v=î±ûµ?¯ ^²|­zO"úÏTžÿãþ:þÀýxýHýYýÄýmþ0ÿÉÿÑÿóþeýMûçø”ö¯ôxóÞòéòHó¶ó"ô{ôçôtõööÍößöîö÷€÷?øHùŒúýû}ýþþQ^$¶ P÷Õ­%¤Éû/g´%ØÿÌÿkè|%ÍaÓò¯4K°tžì*)åwÁÿ‚ÿˆÿóÿ’V7¨ÑÊnÿ¢^kÞoïÌZÅOSSJ-;Tr¹×ÑtʼÿiþŸýTýYýŒýÕýWþÂþƒþý×úø÷´öR÷±ø)úûFûÅúú[ù‹øë÷š÷®÷xøÉùüúñû¸ü<ý¯ý@þ(ÿT½Q{•çœ`a•'ìô¥®)OÔ–ˆ¾2ôÐ[}-"ƒ„ <…‚öâeº™b? Ä2]–Ý6±&³ÿÿSÿ.ÿÿ÷þåþÿ~ÿ÷ÿ@ðÿÎþýãú‘øöòôôÍóÒóþóôôçóôŽôGõöžö÷G÷÷Æ÷#øµø™ùìú–üNþÌÿôÈBwy¶M*Ç Æ(8ÜÏþÿŽÿÿ×ÿXécÞaØ8W‰ÄõdE„íBJ‚¬ÿ~ÿ¸ÿDÞ±eºÊ¬WÖ™PU§F½Ä'  Z^˜ÙÛ:æcš+Ð’TŒÿžþÀý{ýCý ýýoýàýÐý ýgûÃùQøê÷)øMùú~ûòûÂûwûãúúÓøÌ÷n÷·÷}øVù8ú<û<üRý9þÿ\&’ªŒfM6Õ*NŸUÿkš¡ÔgÛqÎ: y™I)ð$ÔÆÝÎ.$­’=üóòµIµj¶ò3Šÿóþ´þ•þpþ^þzþßþ€ÿRݽÅÿþþûù;÷Gõÿófó_ó¤óìó9ôfôôëô0õ`õnõlõlõõîõwöJ÷ø ú§û3ý‡þ‹ÿd›mò«]ò1 Ñ×´wt¼ÿZÿaÿ´ÿ@ò´i!Ùd­§?ˆªùŠV<åÿ)ÿþ þþZþÿúÇb«©ƒB"÷ô¹g¹6Õzìq§«›3¬ UÌ«ÿ<þ ý9üÔû¨ûÇûIü ýcýôüxû¨ùBøà÷_ø¾ù'ûü]üü”ûåúúãø øÍ÷øèøûùöúàûÙüÈýþVÿ;:@îî²ympyfd’ßxñ"æ“t©÷UÄ2¸BކAŸÅ1þ/»]Ä ÚvlÊ` í­hùqåmÔ*vÿéþ‰þBþçýœýý¸ýSþÿÕÿZÿëýäû…ù7÷Põ"ô¦ó¬óàóôôüóãóôƒôéô2õpõ®õÿõwö ÷!ø…ù<ûýâþO"ˆ£”kk¶lj]í,Ê å³Ã+íÿ I¢õ>Šòe¾åÙ£X"ÑKy‡ÿ©þþŸýyý»ýQþ(ÿ ý¹=s{TN5SLÿ3Ð5ŽaNØ<‘ÀÛŵ+6›E«ïÿ¿þšýöüŸüœü±üÚü8ýAýnüëú/ùy÷øöv÷ËøŒú¾û#üËûSû ú‹ùtø÷ ÷T÷Tøhù^úUûEüDý4þÿíÿÿ3ÀÍpðró€ ÕØ<ÿ³$(׳Ó"£;ô€bÐæÞàY;.Slá»<š¼à3­;°[€ ñÿZÿÄþ<þÍýýdýNý!ýêü÷ü•ýþ‚ÿüÿ©ÿgþqüú­÷tõéó,ó óHókófó9óó óióÞóLô¿ô8õµõIöäö·÷ÊøEú#ü%þåÿ#éYtT)#Ãvêê¤>@T¸{–ôdÕY˜ìR£Ñ²B˜ÛMí×¾•x6ûÿŸÿŠÿœÿôÿHÌ%auT—01¯‘q÷3ñòÙãÀ2éaŒxð[Åÿ$þ±ý¬ý·ý¦ý‰ý}ýnýÎü™ûåùtøm÷l÷BøwùìúçûKüüûû~úúûù0ú¬ú<û¿ûùû?ü’üàüUý"þXÿëÀBw ísÝ]å‘'À‹¾ßð%?|È2½(••L…Ÿæ¤¨c “§<ÓG.‘83 ³AÜþ§ý–ü³ûNû>ûcûÊûUüõü¸ý‡þ*ÿrÿ#ÿþmüRú ø ö¬ô)ô]ôÌôBõyõYõþô©ôŸôÖô9õÆõYö÷ö~÷ørøùø½ùàúyü;þàÿBHè7k·Dד-y„,“«ž‰~‘þÅÑø#[¨FmsJ °c ­iJ Ñÿ~ÿXÿEÿUÿ˜ÿ ³:½_, °íÑÀÕí¶åئ¿,ÿzþþýùü/üCû‚ú‚ú'û-üJýVþxÿM“Öÿ>þWüÓú_ú„ú ûûÀúéùKùù½ø™øæøµùúú§üæý}þÕþÝþ”þþ0ýƒükü1ýOþÎÿR®üAyŸ«L Ô ! ó O )†ln¡óþÒýeýýžþ5äb³®\=9 <  ‹ A @ ïW°wÁwŽËЄð*yßöÿ¤þÿü;û“ù+ø÷¥öñö»÷Õøúôúwû‘ûgûñúCúžùùÝøÀø§øCø÷‘ö‡õÖô‹ôôÝô=õ¼õQö ÷Ô÷©øùzú‚û‹ü}ý8þºþ ÿJÿ†ÿÀÿ;&KS£'Õ#iF´Úì0•)ã°~I©DþÊÈ÷]ª¼Ix9ÿþ"ýÅüÍüQý-þpÿ2«ìãÞ 0 + p   ;ÛT /ÿúý^ýý§üMü¥ûðúÂúÔúMûÎûçü&þ,ÿgÿ„þ×ü4ûVúDú(û«üÔý”þŠþþ'ýýû™úeùÚø‘ø ø¸øÁøôø(ù[ùUùùú5ûÂü…þLÕ0+É[ãV®áï”çÉj"õâ¬ÿàÿ|¯ã½Q†vp£Y‘3á < ë Å  " ` ý — | U ¬ 1 ñ ùÇsGÿpýêû”úƒùÆøŠøâø½ù ûRüý ýsü3ûpù˜÷ö õÒô1õÚõZöžö­ö¡ö¥öÉöøöööÖö¤ö|öZö/öööö~÷ªøàùÖúiû¯û¾ûªû´ûüýYþÒÿ*'çˆ7ö.¦ F>î^Â.ÕºÖ  ÷‘ –9âÛ™F@Qÿgþþãý]þÿ÷ÿ5ó¢àµ¦Æ" £ ¼ Ÿ v +ÿ{Z†ÿ þGýGüIûú¶ùºùfúHûšüHþmÿgÿÕý³ûÒùµø”ø•ùú ûGûcû:ûÅúùùðø7øõ÷øSøÊøaùú¤úû5û<ûgûÑûhü>ýþ8ÿ‘Æ<je(ª¨;DÖfa®ÿPÿ~ÿE¸x@æôKþ1£5 Ð ¿ î¤DMµ«UÁN Ë úêÎy½‹ÿý°ûúýøÒøƒù û ýØþüÿ<©ÿDþDüúAø÷lömö–ö£ö—ö[ö;öTö¾ö÷C÷J÷-÷÷Äö²öðö‡÷‚øœù›ú)û3ûÎúPúÝù ùøùøú‘ü|þy*b@ÕX´ìç¨OÜ`Ê2«`a”òYž§sÂi:/À=k}ÿ„þ¹ýdýŽýþÿ{¥è–ߝРW b  Š h Š ñ øE åyåÿÿ þŠý$ýlý¶ý…þßÿý£ßÿ–üyúÑøeøùúÈú¹ú#údùkø3÷ö’õ‘õö÷ø`ùºúüýÚý˜þoÿ"ÁN¤ý*„ kÙ<¡U_”Ä uÊ^%[!l´Ù6t©¨W @ ú # • ¼ ¿Ï(«x& = —qïŠñ;sþ™üûÞù,ùù­ùåú„üÝýŒþNþHý¥ûÑùøÐö4öEöØö~÷øLø=ø)øGø¤øúøùùãø’øø­÷r÷Ž÷5øSù–ú–ûüü¿ûDûìúûáû/ýÔþ~Ê•ù5ÖGÊ8Ž·Ÿ)s™ÑJ  Mœ×üîïÒB™vGÿ þÜü%üàûRüBýÚþštÇ£‹¢ ó 1 è û . — yqm–eÿŠþÖýñüƒü–ü.ý3þqÿ=±mÖ ×þjü×ú6úÐúû¾ûiûºúêù¨øQ÷*ö€õ£õhöŸ÷©øËùíúü²üýPýký§ýþ½þ†ÿE,1Ù™Cß4,€}2Òîþ)vÿ(ÿOÿ"£\“ƒã%x² U Ý ¿ Þ¹¢ºx˺0 « T e0¹òðÝÿžý•ûçù°øÕ÷½÷¬øqúŒü…þ¤ÿ–ÿ„þµüúŠøáöäõ¢õèõEöuöWöãõ}õzõçõ”ö@÷Ù÷=øKø øÌ÷˜÷½÷}ø±ùû0ü¾üÇüqüùûšû¥û\üÕýáÿ)Së!*Kt†u@ß?{´8A™a]Õ/{ {×Üÿ®þRýüôúpú…ú û:üþ—ëï#ɘ¯ i Ò ¦ µ B‚»ãÿFÿ¤þ&þtýÃüFü:ümüòüýýÿ$üÒZwþ­ü¤ûmûüÆüüü†üÅûØú¼ùøˆ÷åö½öI÷3øAùxúû­üjýìýDþ°þeÿå™5¤ë!FÒBÙ‹R)t“Ïâí„A‚»Ùi´åSàŸˆ b ç ¡ Á ’êE1É¢>8¨œl@äV±þý£ûŽú¼ùCù€ùúùûÄýQÿÊÿ{þ†ü3úøgö—õŠõöžöùöèö…ö$öö=ö­ö÷H÷_÷W÷2÷èö¿öïö·÷Ýø<ú{û6ünüNü üÍûâû¦üþÝÿ»QhˆÞ%hœÌîþð²;§&Ë­ÃôÞxç_øÀŠF?Ûþ¥ýYü‰ûûHûü©ýñÿRí) èèë \ § ¢¦³³µÿÎýýEü³û<ûfûÉûgüý þ}ÿ¦Î‰ÿý?û˜ù•øŽøWù9úÅúÒú·úúùî÷ ÷àö.÷ù÷Öøàùû!ü ýÄý;þêþ¾ÿŠ]7!è‘…á.ƒåÛJ9 ãÙßøÿFÿ ÿƒÿ¥Žè´EÝŽ 1 Ä A - v > ¸<Wƒ_eup;Í &ÿgýÇûmúNùrøü÷øù¸úüÐýUþöý·üâúãø>÷5öÛõö’öÆö‘öö`õÞô´ôÛôBõÃõRöËö÷ôö²öƒö¼ög÷…øËù×úƒûÇû¹ûdûû"ûÐû/ýÿ.giLWkå%>²Ý(½ÄuØ!ûž#œï,\4ÿ1þýü¤ûßû.ýBÿáU/j‚ 5 è (  Z í Ww« Ÿþý[ü±û,ûÐúñúcûêûÃüþçþÿ)þ$ü¿ùÙ÷Ðö§ö~÷šøLùxùnùøø øèöèõ1õðôOõñõ¬ö¨÷Üøúûäû²ü¾ýãþ f¦Øõþ©&J7ó „¥Ö3ŒÈt8§¼kÉó«.´$ ½ Y  © © > K ô˜©N“@¹ºöÌŠçGþcü’úùã÷ýö¥öþö øÉùpû’üÞü*ü¢ú¾øÀö<õnôZô·ô)õXõ7õáô„ôRôeôÄôQõûõ‘ööö÷÷÷ö÷¿÷Ëøú2û üVü<üíûûZû˜û‚üþÑÿͬ:ޏÑð7RP+Þs¶›ÎIæ—$1à•2ÒYæZŽÎº²ÿÑþßý„ý(þ¢ÿƒöé 6 ù F ) [  ¶#›åLÌÿKþåüÁûýú"û§ûdüsýëþy†;_ÿÏüvúÕøø‰ø6ù¼ùšùùCø0÷ö±ô¶ópó—óúólôåô£õ_ö÷·÷_øvùÝúEü½ýøþE[m†”mCÓMWYZ  <’Ó!áÔæ< ? ] S ž Å l £ v  ¾Æ}ÇB†zE~ßÀ~ÿGýTû½ùƒøÌ÷µ÷OøŒù)û–ü[ý?ýü<ú øö¾ôGô“ô%õõrõõôRôÎó€óóÃó?ôáô„õøõöýõûõ5öâöñ÷2ù`úGûµû§ûFûìúÑú8ûTüùýÆÿf † nƒ€~©ÿW«Ó¹XÈ-½Œ¡ÝEZR<,Ö}ä&[ž FÿÏþìþþÿ‡‹Æ¥) “ Z  Í ¼ $ ;:OºeNÆþ3ýûÃúÛúˆû‡üþÒªùÅÿý£úùøùúµúkú©ùÕø°÷Vö.õÂôðô”õ?öƒö¢öúö0÷Z÷Q÷÷:øuùîú}ü þ~ÿ·Òâ寰–G¤wêý¼¸ºÃnm•Á÷õï F › î ç žôŽ€  w  ꔹ ¨ í „ ‘ZßñÔwÿ,ýûoù:ø¥÷È÷Ïø£ú¶üYþ4ÿÿÌýßûžùŽ÷öpõƒõªõ}õäôîóßòò®ñ¬ñõñ|ò+óàówôÜôõrõö÷UøŒù„úûbûKûûÍúïúªûýìþÈ91ÒM“¾ÈÏú>¢)°$,N²0A–X¼N¯5ƒÇþÿ=ÿ—þ™þ1ÿàu8³ßiú ‡ £ ÷ Ý ¥ ç ä²v™ô¯ÿþÍüÚû¯ûüŒü:ýÁþª=Ÿ]ÿ±üÙúŠù%ù§ù<úkúú_ùpøY÷9öJõõõ§õöJö†öÍöóö"÷a÷!ø~ù5ûþüªþ6^Bò™#³9£ä¾+cSb‡Šº"áÿ ½²²Íì¼›º Ž  r zð´ ² õé G ¤ w Þ êÙ©Jx„ÿŽý«ûçùŒøÝ÷ö÷ ùçúÕüVþúþŠþýþú¶øÂö–õ5õ]õõ]õ¬ô·óÞòVòòKòÆòƒóOôüôZõzõ¦õöóöø9ù'ú±úÏútúÎù,ùÞø*ùAúüþåÿYSÿKK8AqÊ?Ä:ˆŠQåàò*r{CûÉsã<Ýþþwýˆý;þÈÿ¡„€çu ç * a ã ® ‰  & ê'<–ÿAþQýžüOüÁüsýˆþâÿ{…‰r+ÿÚüÚú‘ùùìøù¿ø$øx÷Ôöö…õÞôfô]ô¯ô*õ~õéõTöÃö^÷øÍøÈùßú ü?ýnþÿÓ×ÕÉ·p“ËÃ<{^^w}nœÿ2ÿ3ÿÄÿÜ~ËêÚþ… Ÿ ü þSßà x å ´  > ó ì ‘ ÷ é ›aLë‘þmüyúÏø¼÷f÷ç÷'ùëúÒü;þ•þþœü¼úÚøZ÷röö&ö0öÑõóôÂóšòÎñ†ñÂñJòóò“óô‡ôÔôõšõwöš÷ÑøØùjútúú”ù#ùù¯ùûñüÿž” ;3ðö3}Ð ¾FÁ^:W¥m©±¦­É¿£5‰‡oÿôý}ýÐý ÿ5`îI ë S m ô ú 5 üˆ)Ëþœý’ü+üPüíü~ý¢þDçëÜþ"üJúeù=ù¨ùéù†ù«ø÷‹ö_õdô ôBôÊôdõÚõJöÂö6÷{÷Æ÷&øÐøÊùÒúèûýHþZÿh‡µ¸Ò»aèáq¸Õî>ˆÀì`Y6Ë/J«BäÖ Û × á  ô _ ^ ! å  îž Æ Ã  ± À T ÂþÿÛÃÿÏý"üÈúßùpùùúü¹ýÙþ$ÿxþæü³ú\øKöÌôô$ôoô ôdôËóóuò-ò<ò‚òÖò2ómójó8ó ó\ó ô>õ¼ö,øXùúTúFú"úúeú]ûýüðþÜgd |µÐèùJnrFìnñ›‘½Y˜¼°r. çÈJšš+åþ‡ýÍüTü©üÀý ÿß[¹3 í P rÕ}L I  ¨ªefaÿþÅýCýýAý»ýgþ„ÿ¨šíþyüïùñ÷½özöÛöb÷™÷÷I÷Èö5ö€õõôÐô@õäõÂöa÷É÷*øoøƒøøùÚùâú2üƒýÃþÜÿÕʾ Xþ¥P$xã9¬ Qëë¦Î|WTÆ †  è â þ ­ Ö \ v C   Ë>  æ V ú à d¯Ä¶…}þÑüûtúÃùnù•ùdú«ûýCþºþXþ)ýeûZùh÷ïõõÎôÄô¨ô3ôtó•òæñ¢ñ£ñÄñçñò3òXò|òÀòIó:ô‰õ÷vø”ù?úoúEúüùéù9ú.û²ü€þRÉÝŸ3µEÁq¯ãóËYÀ#¸›Õ ûÞªz*Ô&Ëÿ*þ0ýüpü³ü•ýÿI›Ät~ß  Ú Ý«» ß Í ¤Ÿß]uÑ=–ÿÜþþˆýýuýðýÖþ¶ÿÜÿßþýJúÃ÷ ö`õ©õ‹öP÷Ä÷›÷:÷²ö"ösõ õþôhõö¬öA÷Æ÷(ø”ø,ùmùÄù[úKû‘üþ`ÿ“ž‡sT ~ÎýÝWÁòoßdú]E¥6½+ ó ' 0 S â { @ ü q ~ I &  Z $ { F 1 ¨ R wpQ1÷þåü4ûúTùùøù¾ùÜú5ürý"þþ=ý«û¼ù¶÷ öäôKô#ôFôdô>ôæóŠóQóQómóoó7óèò¯òiò?ò>òœò{óÍôAöy÷_øðø6ùaùù úÞú!ü¡ýMÿì\m9ô.›ÓÛÕÓʯcù iP`dO<åËØ£r5¥cÿBþhýý,ýªý_þzÿ,“Èþ µ ! ì @ ü  ßû­°ùc¾¼ÄÿgþsýÍü{ü‰üæü®ýþ¹ýüsùÑöõQô¯ô³õ¿ög÷(÷³ö ö<õ`ô¾óÓó[ô?õñõ<ö£ö÷F÷§÷ù÷Ãø3úÛûrýÒþéè{SÆ)h£½èNë#&‰jÀXÙ · ï Ò Ì ð j 2 ý ˆ • ; ~ › ß ” Ú ~ [ - : v à ÉÔýÜÿÃý¼ûÿù®øÄ÷…÷û÷ùŽúùûèüýRüúúù÷Võô•ó–óÍóçó»óAó²òPò(ò/òBòDòYò‰ò¬ò×òó·ó¤ôö÷êøÙùXúXú(úøù.úÚúýû‚ýLÿ&Áÿûĉ3©ö$Wj-­á/„ú/‹í'(Úa®è,qŠ‚ÿþwýÏüMüLüèüÁýFÿêG…» r X ¥ ¿ NH Õ ‘ 9íb:Â|Þÿ'ÿþý6ü¤ûdûŽûPüéüý2ü\ú øÿõúôÜôÀõ¾ö”÷ñ÷’÷÷,öìôÈóRóƒóôöôáõºö ÷uø ùùúÇú¯ûÇü×ýïþ ,4ë}úwãZiDþ¹lõi*©çŸ^´ © ö   - Ø Ó 5 » 8 ‡ W ¿  ƒ ÷Õ:  ' Ì   ¼ S oŽŽ9¿þuü`úØøø¨÷ù÷ìøFú˜ûeüƒüæû¹ú ù%÷IõÙóøò¦òÕòóEóGó óÂòŸò˜ò‡òhò:òòò òKòÈò¥óÜô=öƒ÷‘øeùÚù-úžúLûNü–ý!ÿñ¯%ÚWÉY”¼î ãš$¡@üü1ea(‰µÕ _®úÿèþÓýÜü)üû“û:ü”ýòþÅåQŒ / ò “ j f æ Ê é > 0 ¢zÿ»ë–bÙÿÌþ-ý¥û€úZùùKùOúaû¿ûÿúù÷‘õÖôêô öR÷øøA÷³öèõÛôñó×óiôEõdö2÷9øOùhú=ûËûeüýÔý¥þŒÿpk"çݼ4¬6|OæuýzÈèˆÓà›¢U { ñ ‹ Ì ó¡æ» £ ‡  # ½  8 ‡ [ ± Z   h Ð¥Y7þÿ ý{ûšù=øi÷&÷^÷ø ùVú û}üÑüeüKû¥ùÑ÷ö…ôƒóó&óWómóLóÚòPòòòòòïñîñôñòpò"ó3ô’õúöHø7ùÇùúkúóúÈû ý…þ.×Jj#¥(Î3Ç1 } — r ! –â ‡FUJ½ÞâbÞ£gý7ÿþ1ý”ü}ü9ý5þµÿƒØ5/ Ž í h < [  ì å¶…ÙÄcþÿAÿ=þ»üû¨ù”øê÷,ø©ùìúƒû'ûzùJ÷˜õ´ôîôöd÷lø¤øMøt÷\öúô¼óPóªó£ôÊõ%÷”ø×ùûÉûSü ýÚýÃþÈÿ®‚3ð¤6ä™b~^3þ¨ ˆ·ÈÆ!Mêrj Ù – ñ:ÙÖê  ë 9 ù 3 7 f âÝj  ï  †Žj[hÿ\ýJû%ù^÷=öÐõ×õHö-÷°ønúÛû¦ü¥üÁû$úøö–ô¹óló‡óÓóô,ô ôíóåóïóúóúóèóÈó–ófóJó…óJô›õ\÷ù’ú°ûXüßüsýþåþóÿ@¼)¹ñM§“m¸ÜÎ¥Yâdùÿás²ŸyixúæÞÈh~ÿÄþKþTþÂþEÿu|ŠW$¼cg y { Ì G ä û“Vp ÿyþ¹ýžüGûþùßø»÷L÷×÷8ùÔúáûüòúæøÑöqõõ²õ$÷þ÷`øøp÷ªö{õgôºóßóˆô“õÞö0øùÇúúû ý$þÿòÿ´gÖ[ËËΖj:û¾ ÷ º D ´í5TaÉËfÝœ/ x ! = Û u : U ø ž   \ E  :,¢F¤B9—¢¸õÿþøû³ùn÷†õ!ôNó$óÕósõ¨÷ÑùWûèûfûúNødöÝôÚóxó®óô_ôiôô­ósóóÙó'ôiô™ô©ôˆôgô‰ô%õPöç÷§ù>ûvüEýýŸý£ýäý„þ¨ÿ0à>! Ø‹ä¾™ ?   Ì £  V „Õ[ÒqØ ðÛ {fPñJgÿ_þ™ýýÿü”ýÿ'š”²iØl Ø z · n „ ø1kÕ3ßÿ¤þCýŸûÛùQø9÷×ö÷4øÚùwû%ü|ûïù+ø£öÍõöñöøÁø{ø±÷­ö‚õCôó~óôõö´öm÷’ø ú•ûWý$ÿÉ æ]Ä rÎ…oCë­  ø ’ ûJ–êÿ"Áþ¢\ 9 Á û î ç 5 ñ ^ ‰ ÿ ï g Ã`¥”„Ò¨”ùÿòü°úUøüõô òåñññéòÎôL÷­ùJûûÝúMùW÷†õIôóó´óÉóºóUó½òIò?ò¢ò€ó”ôõSö¹ö¶ö¤öÂö~÷ÌøƒúJüÃýÌþEÿeÿIÿ+ÿ6ÿ§ÿ‰Ë%,Åð G©;æ1® @ ? ¨>库g­øøAÙØäæ¬=O?Aÿ£þúþºawQ¶T1£/ož>ƒol^ ãÿ€þ¼üåúwùvø8ø©ø°ù¹ûžý¡þqþ/ý¡û@úùýøùú<ú¢ù„øK÷Öõô¨òøñòdòìòœówôšõóöoø5ú:üAþ%÷O5Ã3¤9ˆ¦ógˆ´};Ûh¹6]›˜Þ.h l \   Alk2j åLP B ‚„D‰‘ï÷Ä‹$bIþÞûfùðöîôVóòiñƒñ¸ò·ô÷.ùšúÿú?úÖøT÷öLõïôîôõëôaô_óJò‰ñ5ñJñÞñËòõóøôžõ-ö¿öq÷pøéùžûýJþøþGÿLÿ.ÿÿùþ[ÿG…¿Èzø€¸A¸u * * ï•)ЗtHøiÒ,官]1Ë;rœܲæöÛ÷îžzªÏ»ÍŒK|–€íÿÈý›û…ù¶÷¼öÞö´÷où…û;ýFþþýþûçú[ú¦ú>ûÎûü¶ûÜú°ùNøãö•õßô€ô8ôíó€ó™óFôTõ¶öhø(úïû»ývÿSŸ£«oæ;O~­¯¤’I·âæŒf²õ½±¸ÅæM § L Œ¨üi=# E  @ ØUšy=¸ðÐþ^üïù¡÷˜õôÕòJò‰òŽó õ–öú÷õøpù?ù™øÑ÷÷¢öröyötöMöÎõàôÅóÊòüñ«ñþñáòôkõ˜ö•÷ø{ùqúwû|üpý<þ¿þùþçþ¡þ*þÖýÄýþ½þ“ÿ”£º¿œPèZÁJë† [ 6 Ä<¨O,CÏXÍ®JâVçAàÓSÅPȽPvßÔ7ùa[Á$3þ1üú“ø±÷¿÷æø)ûþR4ÞÄÿ^þýPü[üÌüIýgýÏüÁûSúµøúö¥õõÉô¡ô]ô#ô ôbô³ôOõPö…÷-ùöúÚüwþ¸ÿù^Á*/Ý]½“ù,R§"Öxæ,$ù\óÀ¯±ß,© , ™ å  öÛ€ M ~ Ç á дž|ü!°ý:ûùM÷õõìô[ôgôõöV÷ømùÝù¤ùíø*ø–÷L÷-÷÷Ôömöµõ¸ô³óÆòãñFñ$ññŠò¦óõpöó÷hùÄúõûûü¿ý8þpþ‚þ`þþÁýŽý ýþ–þHÿ.-1*ÞY˜Äÿ>¢&ÊJ’—}c)ºSâ~= <!åµNþÅô¤¥ PWàT™‘[Žã_,Ö!·!¸ýûµønöõôôìõ*øûwýûþBÿ«þëýHý?ýüý ÿÝÿjÿþ„ü²úëøe÷iöãõ¦õlõõ$õtõöÁöp÷Jø2ù!úûâûý þkHà à…Mgƒs=Ü(J;BǺÄ*X`IN<aìÍ ´ [ kâ½=w ® 4 æ » t Ñ Ö §SºÒ•ÿ‡ü'úøgö1õhô ôTôõ öèöp÷“÷U÷äöiööököóö„÷Ä÷£÷÷5ö9õjôíóåóôuôîô“õOöE÷eøÀùBû×ü1þ.ÿÁÿÛÿ}ÿÜþþ`ýàü üºüý£ý\þFÿMTCû€å<‡ÞTîpØ6¨Ý‚õY’Ê0aCvWa•'©7j¡ÚoÇç§JÞKóëù³57ŒhÿýüÍúåøQ÷•öåöøüù¬ûÁü ýÁüNü6üòüAþÓÿðX2äþfýôû@úôøð÷ÿö1öŸõPõŒõRön÷iø’ùÉú¼û{üý’ý%þ'ÿØh§Z'È3d`&ªó ‹†ê°rÖ$é³ï[á K Œ k ü 7 ¥ û I Í 7 Š » ô&D!³ÜþµüåúIùø÷ƒöxöËö.÷_÷j÷÷löÊõUõ#õ?õÂõyö#÷‹÷t÷ñöMö­õõ¦ômôHô8ôUô¹ôvõ›öü÷uù ûüäý×þzÿ­ÿ¡ÿyÿ0ÿÒþˆþgþtþ¡þèþLÿÜÿx “î(*æ§WÅðåî*iµäô°:–4Ä‹n‹bNòÛoõ/² t(Ã à‚›<päÿ ý ûmùYøø“øêùAû7üoü+ü¡ûVû¸ûÊüJþ–ÿ\¨T³ÿÔþ´ýqüûïùÙøø%÷töVö´ö‘÷·ø$úxû°ü«ý8þ·þyÿ¡|úJx€iA*1K[…JÀC2 CDÛèqmÕ«ˆ N µ ¡ 6tZ Å ” F × + F K E ƒ´’@þ&ü¿úÒùZùMùºùPú½ú¬úúùø~÷êõ‚ô’ó7óqóôõëõöâöäö‘öö õRõ!õíô¾ôÆô%õóõ÷LøËùuûý„þŸÿN‚UÞÿEÿ¥þþ­ý{ý†ýÉý>þÜþ‡ÿ*¬xý§YËu ™/¿7–„6’c!?J6B¥FñkÕ„ # ­ ô ×nûyŽùÆŠ(sEgþ€ü’úÞøÂ÷G÷Ä÷÷ømú¡ûü·ûùúTúúù®úCüóý-ÿåÿ›ÿÿUþ­ý=ýÙü*üHûgúùØøvøvøùúNûŠü¸ý•þèþ,ÿ²ÿLþ“$›DKKIûðÌ`½*ã½fçSs‰ÀYAyÌ  µ   Û z S | Ø + 5 ± ð  Æ._pÿ ý3ûáù ùŠø–ø2ùæùwú±ú”ú÷ù ùø÷TöÄõˆõ˜õËõêõ×õ§õqõ=õ!õõ9õpõªõÝõöö÷õ÷ù~úðû<ý:þåþ4ÿ4ÿîþþ@þ3þPþƒþŸþœþ…þ‰þ°þÿaÿ¦ÿÛÿcÓWê›`2Ö¶¤M| ޹"ydTayù‡Hd×g¨ ñ ü ( î G ! „ ;žêc)Ëý¦ûÇù©ø#ø–ø’ùÈú”û°ûíú úaùZùúªûSý|þåþþ¯ý£üûŽúúú0úêùPù”øø•÷¨÷Røyùúúaü˜ýšþ;ÿ¶ÿ\äjÑU›ÔÙéÁ©Ž…cÐ ~=rý˜joR6…jÉ™“ _ † ì ²  : ˜ ƒ º ' [ > å t â í‡ÞÖiÿý§û—úáùžùõù’úáúÃúDúeùHø÷3ö¦õiõBõ:õdõ‡õ„õOõõàôÍôÍôÝôçôùô õ/õ–õböw÷Óø{ú<üÖýÿ£ÿÉÿ”ÿ'ÿ’þíýWýýËüžüoügü™ü ý±ý]þåþ6ÿSÿaÿ€ÿ ÿ×ÿ%—.ì²›x\pœ™™ãƒð8ƒÚÙ¯uWý —   = 4 ¥ i J tιa‹Öœ4—ýMû½ùAù‚ùJúøúûÈúú8ù´ø#ùkúAüåýÕþJÿÑþåý¾üÁûæúGúÏù@ù˜øÍ÷÷¨öµöd÷…øú¼ûýþ{þ¡þÎþ:ÿÅÿP¹‘ —TkX+ØH|rtÿÎþ½þBÿJDõfyA"|{1[‰ w â “ x Ì Ú 3 * k ¥ ¡ a Ô  0 ùz°ƒKcþ¿ülûmúæùúú/ûûû<ûú£ùÈøBø øø?ø7øñ÷i÷¶ööeõòô´ôô¡ô¯ô¸ôÀôõ»õÛö9ø½ùTûíüOþ\ÿóÿ}ÿªþ´ýÀüïûLûÛú´úçúpû0üýÖýbþžþ›þvþDþ3þ8þRþ’þ×þ;ÿ½ÿ›‰|üSB²‰Œº540¤»Üba| ‘ O b ± ì H â t)˜ZƒY öý¹ü`ü ýþÃþþOý¹û^ú†ù³ùÚúŒü'þPÿ {ÿˆþuýü üûêúúùøÄ÷×ö_öuö6÷¨øeú,üËýõþ—ÿ½X³Û½”~‡†Œ~xwŒ9{¬ÿ2ÿÿ2ÿ©ÿ6£Ó§<ÝÿÔÿT|"÷½   ¡ c % h  ª ç ¶ 6 ª ôîŸçýþEý¿ûŸúßù¦ùìùpúÏúÑúyúÈùìø*øÄ÷Ø÷Røù ùîùÎù]ùàø…øgøcøpø—øÂøÆøŸø\ø=øzø3ùtúü±ýCÿ™Ÿ9Qð5FYÿwþý¬üÝû4û¼úvúdúyú«úûaû»ûüaüËüPýÞýjþòþßÿÓŸþ÷¤xüÿL qs3b—1îäŸô „Õª”ÿÊEUÿ±ýàü ýðý÷þrÿÿ8þ"ýSü<ü ý¸þ•÷IÕÁ‘ˆÿ­þþšý·üwûñù{øY÷ãö`÷øBú,üàý=ÿ@Ó@Ä0r‘ƒ‡¡ÈîÛ›F±Û÷ÿ-ÿÄþÌþBÿüÿžü6¥B.©¦…ÅŠãÒ‰Mkì¨,Bí;IR_l^Ìÿ|þ$ýÌû±úúÖùúsú°úú#úDù-øH÷Ìöåö÷mø=ù¤ùù,ùºøsø…øùºùvúýú<ûûäúÎúûÜû*ýÌþwÚøÀ:T/à”óG£'ÅÿŠÿbÿJÿ$ÿãþkþÙý&ýüüÃû¯ûü¦üÃýûþàö¨ÒÿZÿPÿ5ÿ¸ÿ4Ãø·´qå‘)Cf®,¿a#þŠZ¯ÜÿÍýVüžûüDýþ1ÿÞþ¸ýrü¸û­ûpü þÌÿ.J$À2›dMMÿþ­üCû+úbù1ùÙù;û ýÿÛF1òƒÖûçÀ¸ÝBaj<è_¯¯“ÇkœžîÊ2môÿçÿQLžÏ+$ϙ˘oÖ± 80ÞA‚§þÑü,ûÊù§øÈ÷÷Èö÷ç÷ÏøRùOùÙøøñööõ©õ!ö¹öA÷†÷l÷÷¯ö‘öÑö\÷ø"ùBú&û¹û+ü¿ü}ýþìÿfÕ  åè­d2ý¸K´ªFèŽE©6­ÿ4ÿùþòþ1ÿtÿñÿ«ŸcßÌg›©Èÿ(ÿŽþOþ¯þÿÉÿAÏ´Jš©f×EøÎò+!iþŽü½ú»ùÁùíúMüˆýÖýýÚû¼úHú‰úìûêýš“é’ç [4‹ÿ§þiýüûoúˆúfûÏü§þŽ/FÌJo™Âá ¾H¦ ýÛ“åÔɳ¹'‚ÎÚ¡2¸Taã¿ËÓzÆÍŠ(l”»]ˆIØ#JIþ*ü(ú†øH÷&öNõÉô¬ôõõÙõ›õøôôóWò3ò©ò£óéô-ö÷9÷õö„öJö>öxößö]÷Ä÷ø2øOø„øù+úÎûßý!JvdÛïÁv.ó“#±BöLƒ¤’Vì|ûöBÅ|9ª±Hu_‡ÃM,Ghj&¢ÿˆÿ¾ÿNýÅPt`wé~j-õÿOÿÓýüjú°øz÷h÷BøÊùbû!üüIûHúgù&ùøùnûý7þÿeÿ`ÿBÿÿëþÿ7ÿÿwþoýü¼úÏùzùåù$û÷üÿC1•žkúZpSðÜ;€¥Š“‹LÇû:¯zÃ^}LìZÝÏü¸Áÿ0×õ‘Ù¾Äß¾>P-ÜgØÿIþ°üû´ù¤ø¥÷¨öÛõjõaõõ§õrõÃô¦óTòñ2ðð‰ðrñšò|óóóíó¤óXó[ó×óËô ö9÷%ø¤øÅø¶ø¶øùüùiû4ýÿ£îõ¸J¹zÑô© U©LArÌ3ƒ¼Ï¶šœÛRýÓ Ì Ùá)£œ°¢†-˨\ ÀBXÚûî&}ÿàþzþðýÊü)ûqù‚÷½õÑô(õTöÝ÷æø÷øøÌöØõõdöPø¾ú-ýçþ y|8Ôÿ®ÿˆÿ7ÿÈþàýlüÉúfù„ø~øjùû/ýNÿMÔôúÄnÿCqfn•¿æ üÛ£CƒÖ7ߪ “áØVËX'\IL c Z ý^z H  :Å û·gþüáùö÷‘özõ«ô6ô'ôrôõÉõ>ö!öxõSôÀòUñlð ðŒð\ñ+òÂò óóóó|óQôjõ›ö—÷4ø^øBø(øQøñø%úÝûÑýµÿmÇÇjÙ"F:þŽÝ(‡ ÖØ]©¯¥žÁ4Ë`9a­íÙ 5 ì / '$`[´7CÖPìøÛX›žxòÿPÿÿÛþcþ\ýÛû.úyø>÷Çö"÷ì÷ÊøžøU÷†õÒóÒòØòðóÕõ øútûqüóüUý“ý×ýRþÿ¢ÿ«ÿ÷þºý;üÐú¶ùHùÙù4ûEý¿ÿõÐRbþb¡¬º¼Éʵn>ÖÙ͹™Œ{œœÐ‘ç6f° ƒ ý K N î V “ì¸áI·3RÒÔ¥xÿ[ý…ûçùŽød÷WöOõdôóáòUòÃñ ñ$ð8ïXîÜíî¾îéï?ñfò ótó}ómó˜ó ôþôöN÷cø(ùVùùæøéøkù{úüâýÁÿQ–8«aÍ9‘ØH’˨¨·ÊÔ€J[ÅaÌß = 6 x µK[…ƒ8݇Mç–MÆRëK¨Ð¥oðþˆý‚üyûQú>ùWø4øPø±øúøìøƒø¹÷±ö»õ@õTõõÑõöuö}öœöëöb÷ø2ùhú ûÓü„ý¾ý¢ý1ý‰üÃûûÎú3û!ü‘ý2ÿãª*gx`+ÏN ’ ¨ ’ N ¼`Ô‹K|Ã+wyƒ¡õŠ. ç è Ÿ ü ë x É í  b%eÝ^ ¿ ñ Á + ;²¹pÝýÈûú¬øÂ÷J÷ ÷ÖöoöÞõ õøó²ò`ñðóîîsí3í;í`íŒí¾íÓíùí,î¸îïàðaòöó¤õ[÷èøúùú¯ûIü¿ü4ýÍýƒþ6ÿÙÿƒG45=?¯ðÀ*>0=¨UJêV§úp`[]Ý a Ù í Ì ˜ £ — — ¾ a ã 8 sO¢/«\—mÜ\ÿÅý;üVûÕúÊú û!ûÖú*ú!ùøR÷ñö÷öX÷½÷›÷÷]ö]õnô®ó•óíóÅôöo÷ƒøù6úŸúöúûû.û^ûÀûYüý²ýIþêþšÿfŒõfôbfó ³#š‡:*qŒrž¾»ªÛL ß Œ I ä /  Å n å  Ž - ´  5 Ï ý ­ õ {ÿÒýËüÞû&û}úÅùßø¾÷=ö|ô’ò®ðûî´íôì®ìµìöì@í€í±íãíî[î¹îOïðñ.òbó‘ôºõúöAø…ù®ú¹ûµügýÞý5þvþÌþ^ÿ;Q‡£ž\ÅÆuÏåÈ× ¨E=4zìŽã” s u : Í = b A ý “ â  I ¬ è.  ´PD4't Õ×]eÿ°ýWûKùç÷S÷Ì÷çø(ú'û³û˜ûûñùµøx÷döÍõµõßõ:ö±ö÷=÷\÷‰÷ô÷¦ø¨ùàúõûÏüTý•ý´ýÔýõýOþÝþÿ­Ãä²,0 ³XÜJñ×›$£þvÞ\+'Pœ Ñ É r Ä ß Õ ç 9 ¡ k’_Ë ã © \ ù”1ܽøQ%ûÁdÐøÿÀþý ûÊø•ö«ô2ó<ò’ññ}ðÇïï²îoîZî^îoî‡îÐî]ïðÚð÷ñ^óõ÷ùúú¨üçý³þÿ!ÿíþ›þ\þ?þ%þûýÛý¿ý±ý³ýÝýþSþþ¬þæþ#ÿKÿNÿÿÿ&ÿMÿµÿSº½H»ÁëH ì k ± "q ¶ Ý ü Ä Ö u 2 Ð ý—Cé¶'nžPRý·Ìþ0ýhüNü†ü“ü+üšûåúú\ùÈøÑøùMùŽù’ù1ù×ø¥ø¥ø1ùûùíúºû^ü¹üÂüæü<ý±ýiþÿƒÿ,ßwò\Æ(¦Ð±Qÿ9þqýý8ýƒýÌýþ]þYþWþ”þeÿ±|™œ»¨!¾Mθ \ u ° , 4 ý £ <Õ³ü³®ÅØô:x“wØ"ÿŒü;úfø÷(öfõÍôeô5ôGô«ô=õ´õö!ö%ö öÍõžõÑõ…ö»÷pù]û ýKþ&ÿ«ÿbö¥e#®¾(µƒÿ‹þ÷ý°ývýý_ü™û×úú^ùøøçøù}ù;úûØûüuýwþ}ÿ Ò7)ŸØÖ²unÂ>Òñè´9¿uSY½´èèJ îªee×›}WõOy¥ˆÿ'ÿÿöþçþÀþ€þFþþ*þšþ-ÿ¯ÿüÿæÿwÿ¾þòýaý9ý‡ýþ¤þÿ°ÿI³ƒÞ  Š|@ÿ¹ý üÑú?úNú´úiûü£üùü÷üý?ý×ýÆþ¯ÿ«W˜@‘ßÿ[ÿJÿÂÿÎv²åÌ€µ©¬ïÅ(âÍ¥ Îû’º«›ÿÚý}üûû¼ú„úTú;úGú“úûûü2ü)üüÎû¬ûÒû[üXý£þ ‡È›öà~ü‘A ¶.~¸ÿäþþaýßüqü ü—û+û¶úúùÁøã÷ ÷ðö.÷ô÷îøLúûÊü,þ¨ÿÜèIëþÿ÷þ"þ¯ýþŸþ'ÿŒÿ”ÿOÿ0ÿMÿÎÿù: éù¼Ú|Ô¸c†pÅHþ Rb9õ–Šâ}ö9R)üøÿ-T[BþˆáD$g!9=>Ê¿êºÿuýtûú;ù±øpøEøAø[ø¼ø‹ù®úüÙýcÿ›êjÀ7ûÿ`á[¯Õܽy\’ÿêþˆþþÿ"‡°ê|>Eß"D˜þ[ýšü.üñû…ûÕú ú9ù°øøÆø=ùæùú7ûÚûxüýéýÿ\Ô0T/³ñøéáâÌ)œ f¥ÊÙéÿðþþ‹ýýZüžûÉúú¾ùÁù úúßú*û1ûþûýþøþ@µ.-•´uÿ+þóüÚû.û2úzùÚø‰øêøúSüßþ¥’pJUIÞQ>e¤Š'Yÿœþìý}ý©ýIþ>ÿŒˆ=*ãu´š ñiM34aºFÙÒ² k í ü m  : |Õÿ.ÿtþ´ýàüQü(ü—üzýëþ6…I6ƒÿ5ÿïþ²þpþ)þãýxýüü¯üüüÍü;ý¿ýIþºþIÿ»0·«ÿþaüÅú½ù'ùàø¼ø„ø ø)÷öçôõó[ó7óœóUô&õóõ»ö÷Bøù,ú²ûýrÿMéÀpT«™ÿw»šùÓa†€~Øwi{zb­@ëæï,øz©’[Zž#q^.ENÿJþNý)üœû'û£úúÆùÜùúMûEý‰ÿô¥-Aœ»ÿþ@ýýüKý™ýRý¶üçû5û©ú†ú ûÛû¶ü…ýþôý”ýýÖüýôý!ÿœlé0_¨ýwòz¿p4  Ó “ Û Ê ÛÜ5µ)˜ÇýDëå±IhÐp-{´69–ÿóþTþ°ýôüOü«ûûžúLúú$ú:únú×úWûüý!þðþ4ÿáþÎý.ü>úXøäöéõ^õ!õûô¶ôEô³óó¼òÃò9óôõ#ö ÷Ô÷…ø=ùú'û„üþÿš6Oÿ–cŸEQ‚¬Ž "ïqÕðgì¼ôÃÙë&sɧ…ú·{õ§Nšþ€Ñ¦ÿ—þþýiýýdü¦û2ûUû‘üVþÑ*úvehoþEýöüóüÏü}üÑû"ûmúEú-ú€úYûdüOýËýÐý—ýeý|ý¸ýþ”þ'ÿšÿÌÿDu¦\åÄ»Î0£èð m „ + c ðZÏÝ€¯ãé²3‡ê«ÎÇRÍÑðBÄÿZ4®ÿ5ÿºþYþþ€ýýü~üãûcû>û‘ûJüCý2þÿ×ÿi»¦ÿ&þ*üôùÈ÷÷õkôkóôòçòó9ó>ó4ó*óFó½ó’ôzõ_ö.÷ë÷¶økù(úû ü8ý…þ¢ÿië9uÇAôé ò_@Ó'TÅPd»ÿ„ÿ™ÿëÿòÿôÿÚÿ)÷°t 1-K³˜6:ÍxEÞÿ¸ÿ§ÿ¦ÿZÿÔþjþ7þ&ÿÔ\TØ_  ¢2k¿À·vµtÿ)þúüü˜ûæûŽüý…ý•ýHýý$ýkýÆýPþëþ…ÿÈÿèÿÂÿ•ÿ›ÿÎÿ;ëÉÒö9pdݽIOî%ž­ÿeÿ{ÿvÿ>ÿÖþKþíýÆý1þÿEvr‰ÍjÌ;>ÿ²þ4þÅý]ýßücüÿû´û©ûãû{ü|ýÊþ)y±ÂdY‰æÿ–ýNûMù¿÷µöHöLö‚ö”öQöÓõ+õ¢ô_ôôõÊõŸö„÷køIùúóúùû'ýeþ¨ÿÄ“þôÐË >·Û õ==Pÿþ6þ þkþÿ¿ÿ"†Ì1´ E¢ üÿga» ïg¯žg}ÿêþrþ6þôýÒýdýHýµýãþþÆŽïf n ! 3 a|"ÓG>ÿCþôý-þÿ/‚™VäºØ`Ù  È^ÒKÉÿIÿÿXÿêÿœ¡½ÖÀiž[„I0ÿyý`üúûüDüjüŠüœüãü{ý™þýÿ¡NÕê|?5­q$ÿCþ¶ýUý%ýúüðü÷üóüÑü«üŽü˜ü+ýþ6ÿd|„>iÏpnÿýæú ùÓ÷÷ÎöñöZ÷Ñ÷!ø7ø%øø%øvøñøfùÀùöù:úˆúíúrû=üaý¹þ)Y4²ãêØÏõUä]nt›°Ó—ÿ:þý(üˆûcûéû…üýŽýrþÿœÿOUÖÇu4Ow$úIlˆŸ¿ÿAÿ©þ[þšþ‰þaþþûý«þ5Uà”¨ e  ž*Ñ ÿVx(ÿHþ¯ýÐýÌþ1˸Aת¹,ðŸû Ê2¡WHž^`èÚd d  ,¬%¥ÿ ýuü ü1üWügüü±û9ûHûübýAÿ¸â [ÈÕÿ÷ýuüeûûFûpû§û·û³û£û¨û¨ûìûƒüpý°þ% í悯 r:ªýûßø$÷ö©õÕõIö¿ö÷ùöªöBöýõö¼ö÷`ø9ùúôúÂûŽü„ýÎþN×;2ÈñŇs’öEÐôÆÅzéQÿ<þðýþ×þ›ÿõÿ#o$¾í)nÌÿvÿ^ÿhÿ×ÿMšfõÿLÿHþtý~üÈûcû*ûðúŸú•úúcû=ýøÿÃ޻ݦ0já ö_EWÿŽþ þ„þiÿnœc—NóÉÎ%ê¸H…vxÒQ4†àÙp ¬ Z 6 Å ñ ” ½^9‘yùÿŒÿ ÿ³þWþþ9þÖþ"¦×t'ô½^þ>üªú†ù“øì÷­÷©÷À÷Î÷Ê÷¾÷¡÷ó÷þøújü,þÆÿ$ >€ìÿÄý?ûÛøêö±õEõõRöG÷ù÷4øú÷ƒ÷ÿö¢ö§öüöo÷à÷kø ùšù.úíúýûqý=ÿ7Œ•#úõY* „ k ÉÓ­hÛW(g%"cµýxdfÓz“zé7=NþwYÿþÄüŠû*úFù$ùÕøÍøÇø ùîùyû¡ýn¢ <~æK¶ÿÖÿªÿWÿ|þhý‚üÕû’ûõû$ýµþM×óoÂÝás×óÔB DÚèQ㥠% [ ß Á  Þ  Ç´úÓÿ¹ÿ¢ÿjÿHÿ4ÿgÿOÊ€z'dÜ3“J“ùþØüXû‘ú&úÌù¶ùÂùæùúúúúfúû#ü}ýíþEwNt{ÿãüúK÷õnó°òœòó·óhôÝôóôÏô®ô¼ô<õö%÷'øùûùÏú™ûüÙýxÿK»POäHÙÓFÐ'ûYj gÖÖÏÿ Õ;¾ä ¬éœÐ4^eÚwžï‹Ðäªß“ŠÿõýžüÑûwûóúÅúàú:ûEüÑýéÿdš¯§s 0âÿÄÿƒÿÂþºýžüÿûû®ûhü~ýÈþ ¤(mL9RáóíÚ™bbÜÛq‚¶ ¹ N .0s  ö |ÿø¼:öÅzCôÿ¸ÿ•gVø? · gõÿÿ­üÓúˆùÇøJøæ÷ª÷¯÷§÷u÷X÷˜÷cø¨ùˆû´ýÓÿŸò§]û¥ÿÊüìùb÷^õ#ôÛólôõÉöÓ÷uø“øCøÅ÷÷ž÷Ù÷*øøîø>ùŽùëù‰úšûýü¨þw`(b—AEÁž…Hô%–æÿÿ‘þÀþuÿ`•—¨ð×ò¬ðÐkˆúìë©/=ÕþZýûªúèùAùÒøïøfùúCü\þ žqçÛX> Íÿ&þXýíü,ýÐýôþó¨%û1z¾õÎ’0®Ÿ$ZÛ¯ÍÉ - æ ¶ Ó 6 ‹$OtÿOÿtÿÃÿ´ÿzÿ4ÿÿ¸ÿ ð6 E e v ˜éé ÿ¯ü ûëùNùãøµø¼øéøùëøÔøùåù@ûèüˆþúÿ Ÿƒ£þüBùö_ôÑòò7òóôõÇõ öõõ²õ£õÔõPöÜöŠ÷>øäørùóù«úÚû{ýzÿ ™3KÛÛrÓL'b­ ¤Õp”µÿçýQý›ý®þŒÿÁ7«q»½N%‰€²Ç)ÐÄ"?ú7ÿ…ý»ûWúnùSøøcøGùñúHý ÈWis×5‹ÿQÿÿ þý¤ûSúsù>ùØùû²ügþåÿê`¶74‰÷7>Ø–T\^~ » ‘“¶ü ‡ ršq~aO Ôÿcÿ8ÿÿ¦MYxB« A Ÿ °Ú÷ÿ²ýüëúú_ùñøŠø.øÀ÷M÷¿ö­öB÷‚øXúnü…þmÝv{þZû}øæõÀóSòÈñ òÏòªóKô€ôOôåóuó\ó­ó8ôóôÖõÁö÷9øÛøÌùûÇü°þ“3n8‚YøL:X2xþâ,w5ƒÿŒÿQ¦œ^Ç"xGS±w¯qšó°¥ÿÍýEü{úùQøM÷÷R÷wøTúãü,­lSÃnËz]ØÿÖþSý¸ûVúKùùuù£úÝûýþŽþÀþ&ÿpÿ”ÿÔÿAž¡béÿ×ÿ¿ÿõÿ©#VŽ Í M ù  T Þ%²#L´õG8Eô ±Â– Û š * ×Þ¤Áÿ—ýüÙúóùPùÊø†øJøî÷¢÷ ÷øù–ú^ü)þÝÿKÝo!þKûVø˜õ?ó¬ñêðññWòïò8ó6ó÷ò¦ò“òÖòdóô!õMöM÷øÏøÓùHû ýÿØØµðN9íãÉ\„Ao >{ÿþ›ý&þ ÿ¹ÿ®†3o ¦;xÜD“I$«ˆ þ¤ÿþ†ücûzú ú'úÔúü(þŸXáf˜<SaÙ ãÿØÿÀÿQÿVþýßûûÆú)û"üxýØþÎÿhÔ"WuœëDUþüC‹ÿôþ‘þ¾þ‹ÿðã6½ ç ¯ w \ G q˜(§ÿýþÿXÿžÿäÿÞÿ±ÿÊÿe…@^“  ¼ h ï «|/…þFýSüœûçú`ú ú¢ù\ùƒùú?ûÝüÂþ¢nØZü­°ýgú\÷¸ôÚòÕñ“ñòÏò¤óhôéôõíôÙôöôHõ´õXö"÷Ú÷}øùäùû–üZþ5á1ÿ,ÙOÊÃJ/2úP-„AÂuþIý—ü»ü@ý¶ýþ³þ5ÿTÖG6]Cðeä®bî§„/X¢Vÿøý™ü³û¾úEú3úêúnü‹þK}œ A ^ ç:±Žøãm†/ÿñýAý)ýÃýÃþ(^€áݲrG;ìŸSþ†$Ôÿ·ÿÕÿ»ié" ­ 7 Ù ž q{4fÿŽýÄüèü{ýþ…þ¢þ”þþÿœpX6— Œ÷ƒ§¿þ~ü'û5úªùƒùPù8ùPù!ùÜø¾øùú—ûvýsÿa7ˆ´ÖJÿyüÒù}÷½õ´ôPôô5õö¿ö4÷r÷j÷b÷s÷’÷µ÷ñ÷døùøùüù²úÝû_ý$ÿðv—/SPfU$Ôø‘œÿTýü€û¿ûqüý°ýGþ˜þ7ÿeýb1gd|¨¾Ëÿ£ÿžÿÿJÿÃþšý ü údù6øx÷‘÷‰øbú÷ü!¬ Q ø F ÝÔérKÍLÿ2þáý?þJÿŠÙìјR¸¥vgb-þ·'‹Ò/¤d·¨+KÎI 7 Ù N ˜ ø"êþÄü¬ûûäû^üœüÀüÙüýØýÿ„,ì—À,®7eÍýÐûŽúÊùVùù•ø1ø¨÷Åöãõ^õ‘õ¤öiøÈú_ýàÿ$u®ÿìûÉøöñóÚò›òÿòÔóÄôŽõ#öpö—ö³öõö`÷øàøîùñúÌû–üýêþ¬¦³‹ìË4  ,©È_š¦)NT[bþçü&ü2üÏü ý8þöþ­ÿÀõ¾÷†ÁÅœ°±ÿßþoþþ}ý ý/üÜú,ù÷üõ{ôìó@ôåõ7ø¦ûyÿL+ “#K?ƒgà-ÿþ›þÿÉÿ¢NÁž[ø–1Ü/7Ú`½U¤u8ìD ‰ Ký¾k †çÕ~p‹ˆkZ¦x¸y±£(ÒÛ#´Ãÿèükúsø÷0ö¢õhõLõõôxôþóþóÅô3öKø™úýpÿRG#ÖŸþ¼û¶øöàóòòò—òóŠóÑóõó8ôšô1õðõºöœ÷Ÿø“ù^úèúWû%ünýÿ%©À6gÄ\w'W‘ { Ï l U ¢º¼:DŽoí¾)· ÂïkŠ%›P Pÿ«þ0þ”ý:ü¯úæøäöÓô5ó„òÕòSô¶öSú:þì† töÿ2ÿÿ<ÿ6ÿ©þ%þ”ýòü3ü¸ûÇûTüDýtþÎÿ8–—W{í?ˆ’. ‘ùs<` l\ê { €œ­Á è à>*ïi”¼ü9G‚5H‘©% f 0 X l {¹½8AþÊü’û³úúmùxøj÷‹ö!öAö÷„øfúVüþÿ`MJÿoýýú5øRõ·òÄð¤ïpïÙïð ñ[ñPñ*ñ:ñ£ñkòóÜônöøùßúü/ý{þçÿk¼@_ç¼H¢rëÌÈŒêÂç¹%Sh%Oÿ"ÿRÿÇÿT9ãã2 P  A § ® t)¸©ÁëY€E{þwü]ú¾÷¸õ{ô¥ôöøìûÒÿa… 8Ù&Ñàÿ…ÿÿ=þýüáúµùÄø„øÓøºù!û¬üÜýãþÓÿ¥=ÀQ…Öä¤Vâ×û¾]ä h ?_çsÛ \ ¤õÅDq)-öèÕ2¸EÙM Q  ) —  Ü@ÞÆÿ þ”üƒû–úßùù5øx÷=÷Œ÷¥øcúvü¸þá»ïM¥„ÿ€ü[ù‚ö5ôÄòòâñÌñ˜ñ9ñ®ðGð(ðbðùðÈñµòäó$õföc÷øãøÝù"ûªümþO;Mó÷™ ËÀ´˜Qîãk¬Û1-ÿÅþîþ<ÿÉÿ1ç9ï‚mG ¤ B q™ÃÐØ£È œÿ“ýuûXùG÷óõ›õ¿öÅøü³ÿspðÕŒ a¼6ÀÜÿÊþýTüû,úúúŽûÔü>þÿiÿxÿˆÿœÿ¶ÿ¬']Hú}ÌÿûþAþþiþÿM{¢è } † Î C ­  ~®’% êÿ÷ÿñÿ)Ôïlü‰ h \ à G  ËQ ÿAýèûéú%ú©ù?ùšøø¬÷Ä÷‹øúóûÚýÿ…NM_›:þ‡ûãøÀö1õrôNô]ô4ôÉó0ó‹òòòŽò\ónô­õþö8ø(ùÃù:úäúôûzý`ÿj:PoÒ·¢Îy´2Ì:b“¼–4ÿæýÓü üžûÈû•üzýÇþT_-à6ß(ÑSF™è¤e²!jßÿ±ü6úÚ÷~öŠöç÷\ú[ýipÖ)©õƒ¢Ù15À_ÿÍýWüGûûlû4üKý|þlÿÖ°NšÃôÊü·ÿzþiýâüûü½ý$ÿ `@„ù³½û4Ž? Cÿ¶þNþ¬ý>ý ý"ýÞý"ÿ£B  ¨Ô> õ·¨´§þºü4ûúùiøÓ÷#÷öMöÍö2øQúÖü_ÿªuþ™ûqùß÷þö¨ö•ö|öGöçõwõõûôõ…õöÈöÑ÷>ùÏú4üwýþyÿULG/àHY~Ñd)iòMÌ(@>íÿ‚þyýýþüíüý–ýœþ¸ÿê‡j[ËœõÿGÿ™þdý0ü£ú>ùá÷‡÷Ì÷™øÁùúú»û ü2ü—ü¢ýPÿ†ODv ð ž ¼pÞ¶²é 1qÿÿÿžÿ†Ã7ªì ô‚¨FU> ÕïpCG†Ü$rh¥É9whk  /­OÔGeBÙ(vÝÿ²ÿ«¡dx¼"©ý¸úŸ÷¤ô)òðïïGðañþò õX÷¿ùèû²ýéþmÿÿlþ¸ý:ýýý!ýãü5üû¯ùø’öLõJô²ó¬óKôuõ÷Çøžú€üZþ!ÖUu dqŠãŽlYR ô „ } gÉM%¯ ܧ&æ‘õDÿ-þHýÏü×üCýðýÆþ1ÿíþÍýÐû5ùöó+ñ{ð4ñ ó±õgø‰ú‚û¸ûû†û¦û<ü;ýƒþ¥ÿ†ú!öÝ*ÔÆ¼›8‚‡‘¿—noQ  µ Y ç   Ê Ž J û ® 1 ž  Bs©÷" P ;€ÔøÀbO Åc£z c¤Îü_ æÿêÿËÿSÿuþ#ýûÝù[øóöªõrôPóiò¿ñ]ñ^ñÆñ˜ò”óô9õõõCõõõ õ§öÿ÷@ù úJúêùùû÷Üöïõ_õBõ„õö÷1øJù‚úøû§ý™ÿ·Ä/Ú> ~ ß _  í » 4 g  h = Á  ^®tAÅG(êzÑÆÆÿÓþþOýŸüøûaû’úù7ø…öçôÄó=ó™ó½ôöøú¥ú£ú|ú€ú¶úBû&ü(ýâýþïý9ý!üÉú¿ùvùøù0ûÚüµþø3y½¯_ × ø œèÌ`Ò : ¸ X  ä ª \  c È J Œ¥‹‘´Ç¾¶I¬LjüðäžA„‡Y_¡á`ª»e¾þÞüúú7ù„÷íõbô óTòòTòàò¢ó‚ôQõÆõ²õõÂó$òð;ï™îÃî¡ïãðòÕòó¹ò:òÝñËñòÂò±óêôhöø™ùûüþ¨ÿNÙÜ)<làªÖ’ › ˜ !.¦lCÊ f ¬ ¢ © s - ~ åõ¨|‚å>ÿ¼ý{üYûÀú6ú±ù#ùø±ö°ô¡òÐðð5ðZñzóõõø•ùƒúbûCüSýiþŠÿŸÎ¥ñyÿñý«üÛû‘ûáû¿ü–ýXþ/ÿ;S“Rn¿  «–þÜI¨ó X Ê V ö ¢ . ¬  g ^m‚ÄA縀/Å6&9¬p*ÉU´Ê¦n1òž[õ$øiEþËû?ù’ö ô3òñ¤ðøðóñUóüô“öÏ÷pø^ø¢÷[öÙôoó\òºñ©ñò¿ò0óóyò—ñ²ððð›ðñóò‘ôjödøVú<üþóÿ´#@ØãžCïM#†-Ü < " V  R  Ëàm…Øñ¶©b1œí0kb.°ÿ=þÍü_ûôùšø,÷kõ„ó¦ñ–ðOð ñÉòîô>÷ùú“úCûüåüþ ÿêÿ³’mÿ›þþýÂý þÿ,‡{kV<M » Z Ð üË2`rn[2'ò·N—• P  Ù Š Çº-¦ù]to{ÿ¢þ)þTþæþšÿHÌõ“ÿ5ÿ ÿÿHÿRÿÿKþýqû}ù^÷;õ'óxñdð&ð™ðªñ#ó­ôö5÷µ÷£÷÷Hö?õ;ôpó#óoóôÆôõÝô+ôRózòðñßñCòüò ôtõ2÷-ùYû´ý*—áÔB ] P 2 Y º < 7 r E¿ó³ç À C   Axïe½ðÐäÁÂÿ«þ~ý\üEûúù¾÷xöcõ-ôqòhð.î…ìvëpë}ì£îQñÆóŸõ÷føñù³û«ý‹ÿyä# –Ú]é×OЦÑG¸‰ Œ ˜ •atìë’™1ÝÍßëÈ[Ò4Añ ¤ P K 6÷” ŒáBÿ,þ¾ýáýeþùþ›ÿM‘SÓÿDÿÆþ6þŽýý§ü¼ûEúRøíõ]ó®ðî´ëêéýè·éëÏìºînðÉñ¼ò&ó&óÃòò€ñÿðÈð ñµñò&óaó(ó·òDò òdòZóÃôŒöŽø·úìüÿóÍŠ I  – É  M È ¡Î6Ë’˜ Ë%à ” © Ð < sW8± ±TÿÇýÁüTûìùø!ö=ô¢ò‡ð!î÷ëäéÀèiè:éðêÙìîuï[ðpñËò²ô÷šù¬û/ýþ¶þ\ÿ«ÿÇÿ¶ÿ{ÿÿÙþ%ÿ¾ÿÚ!©A¡@ü À k "œÒÀ[ßQ¨ÞFˆÕÝYY6çsâw ‚ ´ Ô ü áš=9ÆÚ4—ãÕƒÂÁÑÿÿ8þ¨ýnýýQüûSù-÷•ô­ñ„îwë¦èiæüääûä/æéçñéÇë.íî¢îÙîÎîÉîÂîï‘ï—ðµñŠòÈòbò±ññðmðaðñ=òÜóÛõ(ø¤ú.ý¹ÿMÞ8R  ^  X N ¸ « ( #ƒ7åBò ‡T‚(ŠëŽÉ × †  Z’ÿɱc†þœüjú§øÏöœô<òÍïŒíì†ë•ëJìþìeíYí‚í4î‹ïàñ¬ôX÷—ùbûüñüýÕü¨üzü\üdü²ü]ýþÿGØŸl€ˆ ‹ \ ûk…YÕB|•Ÿ†ol kÆ+ŒÝÔ¿ × ù 3 h A ØPÉw‘]¹h™ÿ´ØPwØJ•ÿnþýû»øùõáò™ïeì¦éÊçøæçÀçôè[êëOìµìÂìoìÙëQëçê¸êëßëí_îpïõïýï¸ïrïqïõïñ¡òˆôÊöIùãûfþÏ>²i ^ Ì ¹$J' °¡ñ:R¬¨êî‘êxƒ  Ô » r êƒä|ed|Oÿýýü]úxø‹ö5ôòð¸îî*îþî ðüð=ñkñØñßòŽôžöãøÝú‘ü¤ýþ\þNþþªý7ýÑü¼üéüýYýþ ÿIÖöu÷W p [Èë¡e¸ä*hyck„„Lú  E m | f-Â-ß/ø:ZŠS™–—ÿªþÇý2ýýýÿütü6ûOùÅö“óàï ìªè+æÜä§ätåÿæäè£êìí§íÐí¬íbí*íí4í¨ípîjï7ðœðuðêï'ï€î„î ïZðòXôþöØù¬üeÿ2ÿÆs ó —œ)J&QÍkp§a—pŸY+GdÆ@«8!} O ™‘åêÿ¦þØý=ý»ü{ûÉù"øö¨óDñ ïí×ëXë×ë)í.îÀî³î‰î£îcïñ¨óŒö$ù8û«üÜý¼þUÿ—ÿ{ÿÿ†þüý–ýGý2ý^ýÎýþ-¬}P ê àDj:µZÌFÏFq*XF™/õZÑ h ¡ ”  2I\!óà 8Kÿ4þþüéû2ûûûÔú#úùr÷2õGòÝîfë,è›å äíãÑäZæ'è²é½êëÝêOê¹éUé7é]éÍé·êì©íïâïðÕï;ïÑîÍîïåï!ñÙòëôN÷ïù«üsÿBþ¹  Ô/)Í9±q©ñ.„bÞ̱ã+…tìÝ&Ð A •Gœ1Öÿ7þÊûfùºöÈó§ðÛí½ëRêåéêKëžì1íéìTììPìpítïòåô÷~ø™ù€úØúÌúÆúâúû0ûFû€ûßû9üŒü[ýßþëp> · å „¿šA§†ïLÏXÊá“ °:6o¿@µ÷ ú I àã-äóCù ¤D¹ ÿ»ý*ýþü·üüòú~ùj÷ôñ!íré7æþãùâ%ãäIå|æ—ç%èè¤çLççç8ç çuèzé¦êÃëìÈìäìáìÜì í‹ípîÃï˜ñæó™öqùKü.ÿ3;C p Bz/rgA_p™ÿ)‡jý/B¦YCA Á†~Ç ßh•hÆÔ²Ïþçü¿ú7øcõÎòªðÇîëí}í.îúîDïÀîî¬íÈí ïñ›ó&ö$ø{ùú™ú¢úkúúøùÙù úzúóúDû³ûüü£ýsÿ×tR c >…l›wÆÿÑ3‚Æ%…µü v ú ˜ _ * À 4 ] U aÊu>OH.Ø×WÞ[äÿòþÐþÿWÿ\ÿâþ½ý»ûÛø0õ ñíéìæ•åwåGæ…çßèåégêpê>êµéé|è&èDèðèôé-ëGìýìtí~íWíí1í£írîŸï1ñ)óoõ÷÷›úNýøÿ±Šb ; üDù1F§t”¶ý†>;¿[W¶4ܦĥá88  3ûpì,Æ¢ÿ_ý,ûhøqõÊò—ðïHî'î©îbïÈïpïïïîbï«ðŸòêôþö»ø¹ùúkú ú×úüú û.ûûòûOüÅühýþ×þöÿ–®Ãf ¸ ¬ ß:…ü<‚•4apr2™á Ï ~ ª é3g[Q °}˜äþzŠYˆþFý¬üzü6üÀûûíù]øöó{ïäëÝèÒææiæ“çé¸êìçì#íîìXì³ë4ëÔêÌêLë6ìXícîïOïï îîÀíóí¢îÄï^ñ^ó´õ>øñúÒýØ+" ® ³Oy3y¦ ÇÀÐs ×GÅa@~àS«È2 k àA/Okÿý’úý÷õ òXï6íìsë”ëMì&í¸í¾í_íDíÇíï*ñ³ó2öSøªùGú›úßúûPûˆûÍûùû'üNü{üÙü{ýFþ`ÿ üT¼ é ¶ 2‰‘@Ýy+ãué6ÿp®Ô -³E“øË 0 ” Ü‘È^YZ+sX¥ÿ3þôüRüüÑû9û]úù0÷™ô;ñ`íŒé8æÆã·âëâä±åoçéAê°ê‚êêéAé6ékéêëiì˜í7îBîÅíáìì«ëìðìfîMð•òõ¯÷<úàü¡ÿ¨ï& Þ ò QˆÀÓþ—BÔ4ù÷e_<DƒÛf¯\éÕ\X  eåÿŸrþü ùËö…ó¡ðî3ì(ëÂêë®ë ìÛëë’ë1ìÃíðÊòaõ¨÷ù×ù6úkúˆúdú=úMú˜úæúû6ûŸû4üáüøýÈÿ •;Á ì ·|ž WUvSªJþŒ} Ô¬Ž8} ¡ a ß }Tœ;8‡ç›ví7ÁþøýËý§ýPýƒü0û#ùHöŠòLîêæ:ä5ã}ã´äeæ3è–é‰êâê¨êê…éþèžè”èéHê°ëëì¹íóíÑíNí®ìdì•ìFíjîðPòóô¬÷fú*ýü'7 × â IsL+ÂÍHjó¼ þEûרåR=•‚€ ñ °Ø§œ¡LYÿäüyú¶÷Þô)òð®îöíîÖî¨ï&ðÌï'ïŽî¥î´ïmñ’óyõõö·÷õ÷ù÷ø4ø`ø˜øðø|ùúÍú]ûüÂü€ýµþ¤4é~ ¥ Hn1¸ }"úÃ^™TŒŽ©mv « ú _ § × ÁŒ?hæ6xxïÀ=ÁþÄý†ý«ýÖýãý¢ýÒü#ûNøŒôLðæë/èšåeä’äÌåçféÎêŒë¡ëëQêéãèˆèºè­éëjìríåí´ííAìkëërë…ì@îwðóçõÇø€û6þ* é &Ö§³ÃN-S¡ôƒ&ÿŽ·§ü€êŒþå2 å Zôé`’'½žÿúý!üÏùîö¢óTð°íÕë¸êÇê´ëÊì¿í"îî.îëîið¹òZõÜ÷ßù$ûÜû#üAüü’ûþú¹ú¶úïú<ûÆûyü9ý þHÿ¥›· — ÞŽÌŽÐ×rõˆümtA.N±dF6ð 3 ; õ R g(%xî ¯.3´þWýrü8übü©üÕü›ü½ûþù0÷Hóèîµê5çúäFäàäRæè·é ëÌëöë ë&ëêùé´éêöêmìêíúîgï<ï™î›íÂìiìÊìäí°ïòýôú÷çú¯ýi+3 6 ç ‘Ù™{Ú¡”Ç4G¶ib@8ckÊ™^ç)[Ù Ú ¡JJó:HÿÍýÜû§ù÷öÿóäð%î;ìëëäë@íaî¤î2î…í)íníÆîÞð[ó¹õ|÷»ø…ùLúÝú'ûrû–ûàûmüý«ývþCÿäÿ¼ ÙPøÙ VZÛñ¤ôDÐZ[Ríµ3Û¡‹æcþ²BQ  Y ­î‹›»¨µ³9kHŒÿ}ý¨û|úÚù¡ù–ùŽù(ù7øhöªó ðÔëÉç‡äžâcânãBåTç9é‡êëåêRêšééúè^émê"ì-î%ð]ñÃñ~ñ”ð€ïÃî›îìîíï£ñÒóaöùÕûkþò–ƒ¦  ”ß Í@Æœ®öF§~L*4pŸbTYñ,NK Y J¯ˆ öþ_ü‹ùcö®òòîíëßéÑèÛèÖéÓê…ëgë ëKêeêbëGí1ðWó öøùÒùú-úõù¢ù‚ù”ùãùMúûýû!ý^þôÿû\GQ V â»%L gÙ9§Fe6†¨Š‰–§‰'Ðs·( A + EåÒ©“•:;aÿŒýü)û¸úŠúiú ú_ùù÷¶õxòŒîsêžæéã“â¢âÆãVå çnèFé\éØèèEçêæúæ§çúè¯êŠìîéî.ïµî¼íùì¨ìÓì–í ïñeó!öøøÓû¢þ†¤Ü ô uo³pÂêQ-‚1Òífij2Aøž¹{½uËÀÚ L C zó’ +ÿ½ü"úV÷Íô(óòxñ0ñ ñ†ðKï’íêëþê—êë@ìýíðÛñdó†ô›õ³öÌ÷òøÎùbú²úÐúyúúúµú„û¾üœþÊMÆr Á  c‰—Ý)C&©Ö»“:•Ý`¥qpªãÈì Á N › Ód+%lØQ_N0ÿÄýJüû,ú9ùsøÀ÷ ÷YöPõ¡ó'ñ$îÔêÌç”åSä!ä³ä¶åçè—èfè³çÆæ3æ#æ®æÈçCéÁê÷ë®ìúìòì»ì€ì˜ì#í%î‘ïVñyó¿õøGú²üHÿæ¹ 7 ©åß??õ~ÍÀ“>ÑûÁG]qsŸÓÀ¢`SN G a ›”D˜/þåûŠù÷"õ¥ó½òTò"òòÍñßð¹ïÅî#îî±î”ï•ðÁñêòÓóÈôãõÿöñ÷©ø7ùÃùXúÈúÊúÉúìú:ûÛûÜü…þž ±‚7 b XHõOim hùN?û¡3nZUgi.·áÞ ¢ R  Ö‰= ÈoùŠÿôý6ü úBùó÷Ÿödõ:ô(ó*ò ñeïPíûê¹è¿æ>åtä6äväæäeå¶åÏå´åŽå{å”åæ çfèÞé?ëìJì3ìØë€ëPë—ëWìŽí,ï#ñ3ó9õC÷\ù®û,þ¼q%¡ Î >\WE>ím98^ý/-'Åò´1Mg˜ª ì ó k¤}þrúY÷Kõ ô¦ó¨óô(ôióþñhð×îuíäìízíFî ïÄï#ð¢ðYñxò¿óöôyöø¢ù±ú²ûÊü­ýuþ6ÿò)šfŽ– v " qƒ‚­Øgï2qeËUFN¯¶SÌ;Z ˜ßq¬ f  B Ð ÛƒLDþaü¥úöø/÷\õŠó¢ñzï-íøêéçJæ(åÿãîâ"âˆáá§à.à¾ß‡ßŸßàÔàÚáãŠäÈ塿-çaçDççáæçÛçSé„ë,îáðqó¿õì÷%ú‚üÿ„ä‡w 9 ÜvØ•hé*d@ (Þ4þ8ßÜðLvƒ ¸ w Œy§9þ]ü{ûaûrû¹úÂøö óið}î íÅícîÿî‰ïíïððúïÒïðéð\ò6ôÐõÁö9÷2÷Óö»ö:÷øzù1ûHý‹ÿÓ@¼Ó~  ¼ ¾Žl%•œ>³Øý³:Wj¾NF=9¥“ÚØ¦ F ƒ Þ‡Ël°þöû0ùHö\órðÆíQëléè$ç6æ.åFäã¹ââ>á†à§ß¢Þ÷ÝÞ ßŽà:â¶ãSäìãÚâ’áQàfßßßòà6ãõå®è.ëfíšïÒñ"ôwöáøqû»ý±¤¢: … ËËúÇ#½¨ X!£!…!€!Ê eu­[ó¦0…t d ÅýÕ‹‹[<ÿpýîúaøö÷ô­ô”ôpô*ô™ó(ó½òÃòÀòÛò‘óâôÕöjøuùºùtù€ø[÷®öö ÷RøúVüÅþ/Xâäu.Œ - X ;¥ÆÌµ´€c®¾† Ï8q{Fø`W™A&}Ÿ­,   Í ,Ë$þÔúT÷ºó™ð*îEì´ê(éÆç7æ€äµâõà6ß™ÝCÜ9ÛÔÚEÛ’Ü›Þ×à˜âkãEã]â áÎßõÞ±Þß?àâäRæ†èœê¨ì¬î¿ðêòÖôÏöúø ûý¶ÿƒR ž  “RW]]ƒ !¬ œ´BÞµµ §ld Y N“ªá[þû½÷$õÂóÁóÕô>ö+÷C÷œödõòóœòËñúñVóÏõÀø`ûý´ý ý[ûZùµ÷ÇöÍöã÷‹ù¸û$þ‚ŸR‘µ p  ¤u8Íj­‚Í¢}ò -A˜­sÇÏ¥q/äXãÌÙõú h \ ü «§ü~ø„ôñîÔëãéèkæ°äÔâåàÔÞèÜ ÛKÙ ØË×sØÚôÛ¼ÝÓÞðÞ:ÞøÜ†ÛOڣ٪وÚ+ÜaÞåà˜ã7æ¨èÚêÊì“î$ð‘ñ>ó4õÈ÷ÂúþbÙÌ2 ~ Œ›Œ]L\D<¥ !• 0BÝ\'ÅX¶ 5 Ð  ^ Ê>ìÿ<üù÷‘öl÷ÑøÿùMúÌù¨øH÷Ùõõ•ôõ­öâøÐú!ü«üü·úÞøûöÁõ‰õ`öÑ÷€ù‹û‰ýMÿ¿æÑåDÖ÷ $  º 4 p r  ‡  E bšA«‡f?;D;ÄËLZ%•äX¤ªhÐ Ó ƒ Â|íÿtüIùžöeôeòŒðµî­ìuê#èÉåxãEá+ßUÝܯÛÜèܟݵÝݦۭ٦×úÕþÔéÔÖá×'Úxܰ޿à¦âwäAæ?èFêBìrîñèóÉöÐùý£ÿÌ kîu ûŸ3{³ºÏ”OÁsºZÛŠIlƒ Î Ä $ ÿ 6 b=ÌÈþ‚û}ùÜø§ùŒû{ý„þ˜þ¬ýCü³údùÀø$ùçúŒý`gE‘Bÿý‚û#û¡ûëü…þ7ÓÌ.…u±A F ï 7 ñ « * [ ³Ä‰ ê • 5­ù=./ÁÝf€~ñÊÌqÑ Û Ö ÍXrÿéû3ùñöBõÌó@òyðšîºìÞêéKçZåUãWáÈßåÞÑÞH߱ߢßëޕݮەٸ׆ÖMÖ%×÷ØyÛSÞ%á¤ãÌåqçÅèøéëì¯íÅïoòBõøühÿ2¯† Ú ‹¿ÖWÇZ‡F‡XÂa+à¿ò È » º 6 ï î Ñ ² p ™ýiþŸûú*úIû+ýßþ©ÿ~ÿ®þŒývülûûŒû3ýeÿÅzߦþQüÐúwú;ûˆüçýWÿØ=L ±„½LÞ @ P ý < Q N  Ž ì k | ê 5qŸÀÐÆÙýuˆ0u*—ÿ,„¸Š< ž Ð Äi©£ÿüÜù^÷&õøòàðµîŒì‡ê’èëæqåäÃâ‹á—à`àåà›áêáŸáƒà•Þ'Ü¢Ùc×½ÕÕ¦Õ×(ÙqۮݰßjáÐâäuå÷æÏè0ëÑí]ð0óRö#ùÑûSþÇÍè& Ç Ã²™F_Fa=~<òב9R¯Êù  š ~ ê  ç ‰ Å!QSý¶û•ûµü”þ<Õ¸ÿ[þ¾üû2û üþ¯ pÍDêÿ§ýAü üáü.þuÿä3I#‰Úq „ O · é ¬ 5 l s û  • K ŸÙÑpòœnȤ³F¢;,‹~»· c À ·N€hgýÐúÃø÷¢õ(ôoò{ðiî]ìhêkèZæTä°â¾á®á7âéâ\ããñáàÌÝ.Û¶Ø÷ÖeÖàÖ>ØÚÜìÝ…ßéàâKã­äæ¬çíé6ì¥îŒñœôn÷Êùîû§þº«Þ · ‘ÓþÅ„…¥0tÂŒŽ[Á 7  + t ¶ ö M > ·ÿVýˆüEý ÿ>ØU˵EóþýýÛýÕþÁ$åÑâÛÁÖþ´ýÌýÿ³¤}ñ;Öë•v£ ï ¶    < : “8Éû S ” š Škð nÒä†èÁâ->õ@å Q W ß ¨ÐÌþüŠù§÷iö„õzôó‡ñÏïñí<ì›êùèfçúåéämä†äÎä åíäLäôâáÖÞuÜqÚEÙ,Ù!ÚÂÛ·Ýß'ázâlã2ä%åCæ|çéëbíÊïRòæôA÷‹ù~û­ýhS}- d d ¡•ûõîU€z¬Ÿ«üHU   y ° Ð  5 Ó • ’Óÿ:ýÏû™û¬üöþ >}µ–@ÿ·þYÿ“4ío {å Ãþþþ»ÿgsi±?5ÚßzC… ! | G | O µ Û Ü Î íÈS s ­ û p€iK î‹Þ-Þ¡õ€`• Ñ ð í ³ PéA(¤ÇýèúIøÿõ)ôªò?ñ¬ïéí?ì¸ê;éÎçræåäã2ã-ãÒãŸä~忯å¿ä2ãá‚Þ_Ü?Û>Û/ܻݠߋáCã­äÜåûæ$èSéê'ì4î‡ðØò)õ©÷Ìùaûëüÿ¨áø½y * ³ iäœoº<WÇ1. | â ) â àÏX ( @ à † ü =^ÿ¬üûÿú‡ü!ÿVrd¦oÿþþ1ÿƒ¦q@ æ W µ[Õ³ûØû. Ô  D ¹ ê 2ýÉïà Y þ ¢I 4 . E * Ð r6ÚTwäšûGø  W m ? Ë•¿þßû/ùÃöÄô2óþñð ïfíÍëê`è²æå‚ãlâ(â„â^ãCäùä.åˆä/ã4áÏÞ›ÜhÛ~ÛºÜßÞ6áoãIå­æ¾ç˜è±é!ëÕì°îñ óöOø‘úaüîýyÿ\o²² ä Þ C ² 1!³9 Qiy f Í Ð öÝ?8¨j2Ȱ´µþý.ûùMùtú ýëÿöÆ‘¯„zÿÿ¥ÿ?ÀSì pØ™ÔÁ›Ô M o ] E ¶ É H ëPOÐêøV È ä  ô7)Û—Q#á‡ÅÀ>%ŽšÛ”Á è ñ Í E w‰cÉÓý­ú ÷Ýô¢òêð‹ï,î’ìÓê éRç½åZäãðáá¯àñà¥á‚â?ãã9ãÿáIàKÞAÜÓÚÚ_ÛÝ@ßjáHãÃäÝåÌæ¿çøè{ê_ì¤îcñ,ô÷Çù+üþÿóãg¤ d  sÜ §ºw¸\@Ç|\ßy ‘ z F °©P[ˆ"¤,•6üWùì÷øÎùìü)ÏÀ–ëþüüPû—úmû‰ý’•N­ÁMÿ£ý_ýþ^¸qË7 ù ' ÷ ´  ' ¯ X³wÎH3;* å ð Ú Í  ~üF9@5.Ommü± ·ï ®À4¡î ½ E { 6kBþûøsõGó€ñ«ï¯í¹ëÇéèæ åˆãâ†à„ßL߽߻àÓávâGâ8áUßÞÜNÚpØè×”ØWÚ¡ÜßÞäà˜âôã-å\æ˜çéë)í§ïLòõæ÷>ú‚üÛþâVê4U { † ì Rå[™BbL’üM £  P A HòôXçÎ  „ ÐOŽýÍúœùàùµûJþW&ÆÉÿ\þÓüðûSüûý{‘;¯æñ/ÅlÿYÿ3P6éã€ÝÜ ¤ ´ 0 ` \ œ¿  @  l v  þ  @G#^¶òÂòÔÊÝÏO{Ý P ‹ „ + |}†åþ^üúøgöøô}ó¿ñµïŒíªëçéBè³æå¨ãâââŒâãkã[ã–â(áßëÜúÚ÷Ù%ÚSÛ'Ý)ßá†â¸ã©ä«åçæ^è$ê)ìhîºðFóöUøZúSüþEÞlé  i T‹JG7ëÍÓT3ƒÖ , 4 ©ë ƒ}ç"®oxÿ©û¯ø÷ö÷Ãø¢ûZþmÜÿÚþeý@ü,üXýpÿNËcò(H8ºÿ‹ÿQ›o¦¦ ä G E — n Á g ‰ù·Ô£b G ø T x # 9 2 ÎV—J }9öD˰Îáyp¡ • Ê Ú } \ ± É£]ÿ9üˆù<÷Wõ¾ó_òÏðçîÝìïê2éçæÎä|ã/âTáákáâíâ ã’ãÓâ7áøÞ•ÜÖÚ$Ú•ÚÿÛ$ÞŠàŸânäìåç-èbé²ê;ì3î?ð¦òaõø•ú³üWþ=`ÎT |  -‰¡TSÊIá ‰ *  K¨p™ f  ±[àýþ€ûüø1øùûúü8þ{þÊýjü§úTù1ùIúKüUÿ† x6 >ñÿ þLý»ýèþ¼rE    U ð   lšR* Ë e v   A ) þ۪"àZ"ÌÙ° k ©  ;’‰þ=üfúæø÷ö[ôHòöï¡ífëŠéîçsæïäã«â]â˜â"ãëãwä]äpãºáWßÉܿڻÙþÙ\ÛlÝ¥ßÍá¬ã#åaæyç±è%êÉëí¯ïòªô?÷ŽùXûŒü8þ‰êê Á* û i P`оCEˆú ¤ , … è § ø P =w³Ÿ + | » ÍžÒþsûaú*û\ýÙÿÞ d?ƒÿ þýQþ)8ôªoIÐ¥›ÿxÿV4e@¡oh!a ä e Å ÆÙ/3 5 Ø  ¥=uL‡ Ÿ •  Ä Ö ÜMô‰°\ð¨bX+;é  Ž © ‘   ¨ ©K`ÿ¹ü‚úêøÔ÷÷ öôò:ðËísëpé„ç¦åþãã÷â{ãgävåMæ±æeæ$åãwà:ÞÝþÜîÝ|ßgáLã冿»çÌèÿé^ëÌìõíUïñÞòÐô÷xù üjþ:$½è§˜ Æ ¦ ®ÌÞd°” © Ë ½ ¾ ' rc>ðÆÄ ‡ ? ´ Í Š…Vþ@ûØùJúâûþûÿ4}þýüZýVÿn Þ²¼TÐÿ±ÿnìù4ü4  a Ž ) 8ð²ÕÓöú Ø F¤ëN ¸ ¸ P à jC¯”¼ki¿#ªáÄ j  s î ÿ E Æ Á;…·þ·ûéùvø$÷µõô9ò#ð(î4ìŒêéåçžæ`å[äõãNä åö徿ûæ_æñäÕâ$à¡Ý ÜÝÛÀÜqÞeà7âÍãåZæ­ç>éë]í‘ïŠñ±óìõø@ú+üþd’Õ¾Q | Œ 7•Kq–> C ¿ ‚  î ¼ ¡ š …Z– N  Ù \ Ž =»ÿ‹üóú\û2ýuÿhhŸÊþ#ý^üñüÝþÈ+} ¢ ¾ý1ø’‚ÝE<¨Ë·âN= h — ¯ y Ð t z W  µ³r” W Y %äÌË©´™ÎÐÖ1‚ ; Î O ˜  s U ¯ ¤"$ýÅìþýˆü’ûnúàøÏöiô·ñîîLìêãçÅåªãÙáÈà§à…áãÒäæ[æóåä—âƒàCßOßàâÒäç¸è êèê|ëì¹ì}íXîKï‹ð`ò ô‹õr÷mù®ûþc<š—7`© ë äDq–³ K þ ; ( à½}ø5–ú‹ŠPýûJúõú ý‘ÿ(& *ƒŠôýâø   & %_„)äþÑþýÿOJQÊ £ × ¹gD- £‘²¿ H %¿+cí©s ú  – ov„ÍÒ+¼·—Æ \ ” i R  ƒ ˜#ËþUûMøøõgô[ó}ò”ñ”ðrïîÀì¿ëåê)êé9éOéËéxê9ë»ë×ërë¸ê‚é´ç—åãÙáÕàžàáâ“ãhåEç éùê¥ìþí)ïUðò_ôõöíù½üSÿ­¨™ŠíŽ@  © ‰  Ý _ ¶ ¤ i*òàŠDï׬&! W ¥Xk$¾Ëþý/ýhý+þ–þþ5þýÕüUünüVýÿvs& … q = U ¯ ] < n ª ª0APA dÉ_€›› p Q ˜ò.Fê l w  ( V )ƒv™qPçM›6¦ ºš¼³2n:“_…Vÿÿüû¦ùÿø ù+ùhùFùœø:÷õJò>ï_ìúéAèç¶æâæOçÈçÑç;çæÁä°ãã«â¬âìâIã½ãAä忤ç®éLì@ï%òdôÀõNöGööîõüõ÷=ùBülÿ@1\# :WÏA & ý ƒ ’  ‘ µ \   ¥  b–Î]DòæÿLýúYø¤öOöI÷JùÃû#þ$yK¡ýÛ,ì¦o å ¨ Œ ‰ à es ‡:ù›b[ E ÎCM¸–Û‹ÒÀ Ð , d#p8 I X ð I … ³  K | ‹ H î ¥ f ­ 5 Å ,® ‹  \ ”)¿­þýÀûxúùu÷gõÊòèïÏìãé5ç`åäÌä¸åÝæäç|èÆè¸è6è‹ç ç©æ\ææñåÊåFåQäMã±âáâ8ä[æ×è ëŒì$íìì¦ìŸìjíŽïôòt÷ôû¯ÿöõ‚ê ¾ ] Õ ûý›A‹ ¿ ? 4®l±íƒ¼$ †`d*¨êì²xÆ¥8X´²€Ô{L›?îE …¿bvJ#Õ&  Z W & Í ­ ú ~ D ± õ ` ŸŸôíÿ>ÿªÿö%²tí É oéOz!ª¸Žt¹d)•­ ñ Ó  :Œþüú?ø÷uöö±õõOô•óæò!òPñmðsïùí<ìˆê<é†è9èÿç«ç çýåUäPâˆàVßúÞQßaààá±ã©å¯ç™é:ëœìÓíïËðõòyõJ÷ùœúüÛý±ÿ>ø¤»¯¥`B Í Ù @ ùþðä¹”ôÀoʺ  Þà ³ 1 µ Y o ¨&qçÿáýüæû¾û ü¾üâýÿT])ÓŒ><tÔ$ H ä À  û Qž˜ “ f è !  ­ d = x ó f « ‰ ™  p· Y­ ‚ p+E{ÊA?·8®^{ È ç ³ # Lù·ÃãÌÿuþ©ü¨úžøœöñô¯óßòòòHòˆñðï}íêŽçåHãdâ@ââîâoã›ãpãâââ-á³àáâ¾ãøådèÜê:íMïGñóKôøôËõ}öK÷møú’ûZý)ÿ5˜® ÎøG 3 d × Y ç «  à = d B 3€ á(¼NlÝÃ^¤+Ûÿ—þGýüû•úûøŒ÷¶ö\öãöŽøöúÀý£ˆê;m߉ˆñdÄݰ{t´= 4í+ © G.*y8æýR£Õǎɘ;À  G =÷ƬzŽuÈ<Ž» Ó & F +  Bq.x{ [ý”ú.øJöÇô¬óOò,ð`í0ê½æŸã|á³àáârãÍäÑåQæTæ<æ1æAæˆæëæBç…çúç|èÄè é}é ê>ëÆìpî/ð®ñdóFõúöløúZû¥üƒýIþTÿûp{W t &ÝåÓ`ý cÅ—– Ø ®Äœ®Ò÷øþiþ’þ ÿÌÿŠßZþ}ü€ú~øÐöeõVô¾ó~ó«óaô„õ5÷3ùrû‘ýAÿZÑÙŠPpEYÓ Ð ñ Ì H£8QôÊžï„xçðM".è‡_FN˜þPÔp.ÊË ¡´ Á ß ù=Ï—€ðýdû“øžõ®òÜïcí‘ëpêáéÑéïéçé¢é&é‘èè­çRçþæ\æ{åiä‹ãHã‘ãä*æØçXé¿ê¼ëWìÞì¨í¹î,ðÐñô"öö÷{ù‹ú(û üÚü¹ý®þàÿÛÃîôÒ7 ’´_6è « ºmú´• Iÿ^þ÷ýmþ˜ÿÖŒØþ‰üú"ø÷¹ö ÷ˆ÷ï÷ øØ÷B÷µö!öÞõüõÉö=ø'úbü©þ4ƒº%|‚C2*|ªq ‘ Õ ¾Ì90W|' Z¹‚„Oú%¿ká— €yá +¿f¼OÁÅ$ŽiÙ  0dÀý¤û&úBùvø±÷þö˜ö2ö÷õ„õ¢ô4óñ¿ïîžìZëyêêµé+é®èþç4çûæoç€èïéIëüëqìÆì í¬í·îð ñNñùð›ð×ï(ï†î¹îâïòòôÈ÷úªûýßþäõÅþÔØvKóÒ ^ Z ¼ ’ Á  ¯ * ®kÃ|¶§m%þüÙúzú=ûyüªýþ­ý#üú—÷aõ§ó°òÁòÏójõòöö÷uøøÌø’ùŒú‡û–ü9þ'k¥~ÂÕ4VFÀ‚)S` 2 „ ?ó0P„f#e$ì!±¾4Mhyó#=ë ß b Ñ ^ 9 ü —  ZŒ¦ÇNùcªÐ±#4þòûåùá÷½öìõ1õ÷óSò=ðØîîYîî›îLî$î îbî‚îTîÏíºìNëê3éÄèØèCéðéÝêÑëEìZì5ìÍì<îtðÎòGõƒ÷8ùâù·ùðøBø"ø$ùðú©ýW°e(ÜnZæý“Íš à üm’®UÝc1‡ö-øÿþaýþgÿö~ €sÿ{þ­ý,þPÿ ç†ú¢@2 ÿý›üý¹þ•ÿ#{êyÎÞ   D ¥ #  V ÷ Í Ô 5 ˆ ¡ § ü áµ ï¤-AÔ€jŸ  Ø N£µ4M _ ^ Þ#{Êu ¤ µ } ŽD+ Öv,­çÿ*þãûù!ö—óŠñRðÀïìï°ð=ñŸñ±ñ´ðï»íòìóìÈí ïað±ñËòdóTóíñùï`îPíÛìiíãîôðóô™õöö×õÒõö¹öÄ÷ùúÁúÖú½úÝúûãü”þ#Sö¾ΓÿnþþÇþ™$Çî{ 3 ÿ j ? s 2 ¢ 5  5 È é $4ûÿUüûÂúâú5ûËûÿû™ü0ýþÿ/-]ø×;OZ.¶F•0ÈoBÌDÙÊýSù™q R Ð ¾MAE± ¯ K ñÙ  >tOTÇúfd t Ó  % ùüâ`ž %©8ÿ©ýAýÝüÚü¦üRûsùÊ÷Kö_õ´ôwô!ô~ó®òžñ^ðŠîhìïêêMéÅè°è“èÚèmé7êëPë'ë¬êvéèÇæ:æSæKçàèáê?í±ïBò—ôRö}÷ø–ùrúûœû)üvý/ÿx÷bOa  e Yêrù ø_ÏI¿1õ ×0ÚMýo(î>£ÃÿÅÿÔu…#!²R›š½y$ßÿ8ÿPþIýüû|úYú¬ú>ûºûåûü¢üIý4þ0ÿI}çQ % ñ$˜Ñ?‘P› ¥ ?Š£60W˜GZ‘4—CRà¯ Ò ð Ñ A b ² |MÖó CÖ¤ÿný’û†ùW÷þõÎõ¬õ3õFô¨òbðìí³ë³é èÑæ®åZä½â>á3à‘ßußàRáöâËäç2é”êAëëŒë+ëÈê–êë•ìïAòÙõëø}û§ýeÿgpþà«Æ^ T X9ðÔ ï U Ó8 ò À l s û Ã Õ ¼ " EÇ Ÿ Y h S 0sx¦r¬*œþ`ý–üüŸûöúêùôøMø¹÷˜÷Â÷&ø‹øLù˜úXüÂý»þÿÂþ™ýü·úüù&ú†û÷ýÅQ€üT› õ ò “ à c –œ|ª8ȧFèä¶Žœ>’"DÁ ¹ S T W ø ü t ÇëÀµU€ÿÿ¥þþƒýeüØúXù£÷àõô;òþïÐíÅë+ê5éºè•èÌèAéÍéêµê>êQéAè;çOæ¯å™å)æ~ç#é>ëµíªïyñ[óìô(öÇ÷¹ùü|þ뼓լze†^A"ŽÕ_8(n¹= ˆ ~o’ q " 1 k ÖA­âµCµéÿ‰ýªü&ü‚û®úúHùÓø×ø'ùÔùrúÔú$û¬û½ü5þìÿÁ©¹î×üÿÊÿ†"5Ž(0 Ñ U   _ " | 1 ŠÆýh¼Ð ^ * × €èo1ö<Ùß± Å ƒÚ¨Æ ¼ ìà•F>R$À¦Üþÿùîô‘ð‹í)ìLìgí«î>ï¾î<íCëCé˜çQæå äyãããäòåÍçÅéãëíí¡ïíð¹ñoòô“öªùWüòý£þ²þDþ£ýªü|ûqúú%û€üxý±ý@ýýgýÒþá¹2 ïPz01ò>Ù¥¥ ‡ÇýÿÏþþwý ýÕüŒüZü üSýþŠþ¡þPþ¹ýXýnýzþd£|”~rsB”þ„ýý™þzÖ(  ÁéÜÊ6 & ^ U…-N ¾ Ž " V Ç ’ MeL|EÛ4Íñvþ8ey \ »  ‰ ö õ s ¸ ƒ Wþaù˜õ(óò%òÜò\ó óò0ðßí§ëÎéYèzç+ç¬çêèyêsë.ì¬ì>íkîhïjðvñÐòÀôíöÇø"ú;ú„ùøå÷(÷¦öPöÔõÜô¤ôOôZó‹ñNï9îxî{ð ôLø#üŽþ0ÿ)ÿ›þRþ–þ‘ÿFc½n¿JÓYÿúý ýýmýgþ­ÿÆÕÿ3—`§³ £ø/XŲ˜þWüëúˆúcûðü7ÿ–i£PGÊѯîê Í(êE:’a(wÎ&>1On¸°¼ ‹ 9 – A ² B M C ´ ¡ ó Œ H õ  q Ë ÿi“ÿüùëö›õ—õ§ögø,úbûû˜ú»øKöóþðïCîïñAóõö÷÷öö÷S÷ øBù:ûåüÚýoýSü~ú­ø&ö×óòzð„ïÒï\ð;ðïíŠë,ëöëìíøðÛôšøuûý÷ý~þTþþ ýýæü5ýÇý–þTÿªÿ-ÿ0þÎükû‚ú.ú¢úüû þ( 7ë÷AGtØÎUgjÕÉ8ÿÇýÄü*ü~û,ûû>ûÑûýoÿþµøK$?Å`  Ò QsøÞe s æ m ´7ÈOÚ: t þ;pùF Š ò } ½ W Û Ç ú  ­ j%Êÿ¦ü*ú·øøÝùþûXþ­3ºþ_üîù øW÷Vø¾úrýe÷**j?ÿ7ý#üMüµýsÿÆv€ÿâý0ûøÓô6ò!ñgñÑñ{ñ ðxî0írìËìbîñúóàöhù3û²ûûçùAù!ùùù ùXùµùúãù€ø@öô=òñðañ;óÔõ‡øû:ýÀþ!ÿ ÿaþký’ücüÖüfý™ý‡ýzýƒýyýšýÙýôý;þŒþCÿ>ìÞÄO8vuÃéí Ì ´ ü J©{ê~  ù ›â7é˜  û K Ç5±p`†wÛ † › Z ˜ © A Y § ª]¥¨ÿêü»úÚùúYûJýkÿüu,þ¡û`ùmøù%û|ýûÿˆ#•Vñ}ÖEå~ås Q Ð zvÃÿßû!ùBøý÷ò÷m÷—öþõìõìõ(÷ïøÄúùû¾ü{ýþØý4ýzü¸ûûûùHø•ö“õÞô6ô óCñCï`í¨ëêOêëÈì3ïžñCô°öEøëøùÔø4øŽ÷[÷m÷–÷û÷vøLù†ú§û¯ü'ý—ý$þžþ(ÿ4s±û^ïkW i ¯h ëwí Ó Y ý 8x 6 á ² ¦ µ k ï~Ó¾4ÕÓ'Á4+¹f W >hPæó… ­ ¢åƒ~4ÿþnþ¸þ,ÿ@ÿ˜þ6ý ûŒø¨öŽõ³õ&÷Ûùòüïÿ¨¹}ÏþÈý þûÿ‚®Á ž Ë)Ãj²þþxþ±ÿP¯ÿñýÖûeú}ù¬ù4û\ý ÿëÿ²ÿÿKþHýMüünüïüßü1üæú|ùû÷öòó®ñŠïçíJì:ëJësì¯î¤ñÏôØ÷Wú»ûEüZü¢ü<ýrþnñ‚EïþºýÛümügü+ý´þœVZÄ5íÿqÿãÿ w'×”oëúÉËE‹ô‡R©6 - W !:uþÓüUüüüeþêÿM…Yïh<nå F Ð ^ ¹ ôx¢ÿ`ü&úVùUùú;û²üÁý–ýü úé÷ö´ôtôötùhýAoéã?1_ ® š Ÿ û - × I3pÑ!@ÿ¼ý¯üüýÌýðþÌwŸß‚-âédéU3þ/û<ùø>÷pöHõÂó®ñBïEíÚë˜ëýì¥ï>ó÷oú„ü=ý8ý¶ügüŠüìünýÅýìý¬ý8ý±ü/üü˜üPýþ‹þíþ„ÿ”ÿ ÿÐþÿz˜ŒfEA+°N×h š O f9q€ ’ ® · ö ‚ EÖÔkfwÿgþ¿ý³ýlþ±ÿLò•ô_§%®ÿ*ý›úKøÓöcö’öŸö+ö'õÍóò]ð†îGíþìÝíšïéñ÷óŽöù¶üÔÿ‡ - ‚ ™ Šä¦Vj  Ÿ ¡Í­Ù¨=…)þºüHüÞüÅþº\&IOóþßÒþƒ÷·%Sÿ†ýàûDúùÿ÷²öðõ˜õZõÓõòöˆørújüRþîÿ?‘®pˇ©~e¬ÿÿcþvý ü˜û»ú(úAúúúqûáû¥ü0þúÿ8xD?2ãôb{:¼éÿ» Î Î ÷É… Ï ò Ox’n2þIüVûÒû\ý†ÿèM|5UXþ(údöqóZñQðoðqñ‘ò#óóŸòäñ´ðï\í7ìÿëí ïTñôûö²ù9üþ¯ÿò;üá_ Ï  D ® V ,Æ) õ‘}ÿîüû3úHú÷ûùþr?Q1áyå¨ý9äû‰=Íþòü{û úñøUøø¨ø¿ù;ûàüzþÓÿøeá´Aêƒ4KWpíÿ þ¯ýÿü}üüûKû¦û·ûÄû[üéýN€x­±’@* ¬  * Ù … $ ¢ œ ¦0‹¬' ¤ A¯mý]û`ú·úüþîzG" þŒúQ÷ŽôPòððËðÝñTósôÜôµôôãòñïBí}ì•ìäì©íBï^ñôöùAû™ü þ³þ²ÿ5š·C6vQºÿŠýÎú½øU÷öcô®ò°ñÃñóYõ ù2ýH’ Nb“ Z ¢ ò ¢ > ú b ’'Yf­ÿiþzýKýÂýÐþ9Åk»î:¥ï  O ¿ ´ U—M3dÆ4çb³µÕ"øñâWî9õœ ò ¼ È Ý ' B H . È Ÿ [ C  z Á  ~¢©´§ÿ[ýÖúFø³ö¥ö"ø‡ú_ýTž`Ø‘þûñ÷8õ3ó™ò<óÄôJöM÷Ì÷â÷÷˜öœô<òð¶ïsï°ï­ðµò9õú÷Šú?ü+ýÃýâýÞý3þnÿ=Wï 6Åÿ"ýÆùÀö‘ô6óÊñðÔî“î)ïÓð„ó#÷žú.ý`þwþ¡þWÿWñ0ž>ˆéÿêþþ•ý ýdü™ûçú‚ú©ú°û_ýcÿ÷ ÂžE ¥ ë  † é  ý æ p ^ G › » ‹  Òöv } h ñ ý D > Õ 2¡,¢ž° S˜>ž•› L ¬ ;€`I h H Ïû]õþÎü´úøðözö9÷Öøðú(ýÿ R|^þ¶ûùšö^ô”òŠñNñØñxòâò ó\ó®ó´óðòñ!ðï;îõíUî‚ïéð²òöôY÷›ùûuü»ý ÿK•ƒçv`}DeþÌû–ùK÷¡ôGòñëðòñéó¦öÚùvü«ýËý[ýjýÿýèþÚÿå°èVµþýRüû¡ùOøéöRõ ô5óó±ó5õ]÷Àùüþçÿ’Z¡ l ä š , © – Õ 7 Ø q Ë  Ç ¯ ¸ y J—Œ.äfyáTîÈw¼)$º–JŒò„«ª W ¥ vïWþÌû6úäù¶ú1ü÷ýØÿ¤ðú—0ÿ<ü#ù/öTóëðwïìîúîûîïîÀî—îUî‡íìkêNéßèé•éÿêíyï6òõg÷ ùúùúêûkýqÿA†žSüªûœzÿðüãúù¢öYóÉðWï2ïðVò~õ’ø£ú¯û°ûÿûjü4ý\þÂÿb²Í&¸þný ü¨úùy÷Ûõô°òÈñ¨ñ€òôiöÀø û5ýºþ6ô«°aW«–è…1„ðíßÎ ¿ ÷ Ì  € ú Šß÷Ä[¼7ÌLÓõíCòÖ…¡ìÓÈ2ƒ Å á΢ÿÙý þrÿ…¹¿R ´ŠîýGú¬öBóÍð{ï0ï ïïî¢îcîîkíì<êuè„çwç(èyézëÜíð¤ò³ô¶õÀö¡÷jø¯ùüþ™Á µLÙ™{þÛû©ùøö!óð9îí-íƒîñôôcøúàû™ü8ýõýƒþ ÿ«ÿ€Ô`ÿÐþ2þ†ý7üPú'ø&öþó[òvñrñwò€ôÒöù!û±üþWÿ1ž¼ N Ë‘Û ñp+rڱο³ ó ª f…4Ønúç腶²Êk¶ó —Ü& ž 1°eð¼zê¦xM œ u ÓÑcÿÎûuø¾õUôôôôÝógóïò*ò¨ð»îÞìÁërëëzì^îŒðó)õ(÷«ø9ù…ù‚ùÞù"ûý–þpÿ?óÿÿ)þgü0ú=÷¢ô ó“ñHïí_ëdêcê:ë_íœðô¬ödø…ùpúZû:üÜü±ýÐþÿzÿçþ>þþ™ýËü{ûÇùõ÷àõþó™òÀñòSó`õµ÷ú6üîý ÿŠ<Ìž{ÞàÖT)U§“¿ãenû >WF = P–”Q²÷E¿AkšrèÜŒŠ”LR„F¶¹YÌ ) t© ]  xîû Y U Ä ôĽñý=û(ùð÷Ê÷ø'øÛ÷M÷“ö¤õøóØñºïî‰í¨í}î#ðlòõô`÷nùµúbûFü{ü™ü‚ýfÿÒ LAÿ±þRýû¸ø÷µõ!óCðúí{ì.ìäìZîñôPöˆ÷ê÷ø«ø¤ù¹úü”ýÖþÿŠþ¹ý'ýšüÓûúúø<÷õØòÎð<ïŠîï¸ðÙò7õ‰÷Šù û‚ü}þ°ŠË(Ôô²¤÷ž’wÎŒî¤n%‰˜ ƒ á F–© ]’VÂõý|¤Šê4Y»'ðAá.j ÙJ¬âHÌk ±Ò ‰ õ Ó ÄM²ýûZú7úpúaú«ùˆø÷wöõ=ó‰ñ.ðzï[ï®ïRðáñåóökøúRûÿûFüŒüIýÞþ{s a¸ú¾ÿ"þüûùãö–õÆóûðÏî>íËìiíåîgñLô¾ö`ø?ùáùxúgû;üþüÉý¨þøþ„þlý‘üËûàúŠùú÷öâó·ñðMïïãï»ñ"ôpöÎø¹ú<üƒýÿÓ³ÿ«‘÷äüiy·r3æ2·àöôN\šF µ #æ3€Ýˆd9ö*P-bvS9ïYM 5  ´kïØëèÑ ê u ¦6øý·ûOúùùaúÝúû˜úúGù÷÷íõŸó@ñïúîï ðòHôéöú€üþ·þMÿÙÿu¤l{BHÿüºùXø÷¡ô#òæïÇîñîúïÅñRôËöÄø°ùíùöùzúæúƒûeüoýþòý%ý[üÀû ûúù¡÷ÓõàóÜñ.ðïîwîAïüð2óaõš÷gùÈú;üôý€ÿüø7)¹:ô+rø‰<L:hìúw×®Ý © #Ñ9 6žŠÎ”v9Ùݵjq9½ : ŒëœT僦s ‹ / { Ϲ¹ þžûùùzù ú×ú+û¸úÜùÇøW÷}õQónñ_ð@ð²ðëñôóPö‘ø/ûbýûþåÿ®,£GpÂQèL.ý¦úùŒ÷.õSòëïœîrî§îðÊòœõ™÷æøIù|ùäùgúðúØû¿üµýþÝýdý ýŸüŒûçùè÷xõóáðhï‹î·îð òƒô®öø9ú}û,ýIÿs˜ù†oðZG¬¡¶Y˜ 6ç,vѼ!:   ù í ‚ á OÚ˜©*ÖŽ%ýŸ“í K™ ‹ +Ã\àTþü7ü{ýìÿǸ_< ‚ $ h()~ýEûÐù¿ùÐúRühý’ýHý›ücû™ù`÷‚õ[ôçóôüôÂöÎøßúFý(ÿij)aNkƒ# ùG^(B¸ÿœýü•ú¹ø8öÇóòòò5ó•õ$øúòúûçúÖúùúrû‹ü˜ýŒþÊþBþoý“üÓû¢úéøÔö¸ô6òõïÔíSìÏëƒìî'ðvò¾ô˜öù÷ù:ûý¶ÿû0ç#ÿfþ4þgþÿQàÆ:Êd÷ Í+é v ® t ã =Aq¸5¬ˆ¯1[¸x[µ:2¹  {;ÐZ|þÕýsþk'Âá) úXxâ*ýÝù]÷%önöøîù<û¤ûû¯úTùƒ÷‰õ˜óVòØñÇñ-òóªõ<øÐúýµþ¹ÿ_Æìæy¼–üùáª:At~þoü¿ùÁöXôFóró^ôòõø.ú¦ûüÑû¶ûôûüèýëÿñºÝ7‹rEþEû–ø'öæóòÄðið–ðéð³ñÜònôöÃ÷rù&û«ü'þÿ ÿ‚þGýÛûìúû’û\ü,ýèý.þ|þÎþ)ÿ^ÿ;ÿÿÉÿ7Ãçšyi|W  À “ ¡ ² \}¶²|Èp™Mµå î ¾ ‹°òz¦õ%  { K *  Nnýþôü¨ûyû;üYýþÖý(ý«ûÊù¦÷aõRó¤ñ•ðŽðjñeóèõŠøÿú3ýÎþUÿŒÿÔÿ#löRÞ¬mŠT¸ÿ$ÿ,þÛû„øëõYôûóôhõ´öøÌøÃø‚ø¼÷8÷`÷‘ø9ú7üuþ¢úëÌe+¹ìîCþÔû½ùø÷˜öàö&÷Ý÷Õø†ù±úâûýü&þ^ÿeüq®À&Ú}=ËÙÿµþ¥ýsühûòú}ûöüéþµ˜ÀÂ’Ì_C˜Dù_ r Û ! ²  4 ª ^ ø â  ‚ ¢ †  ÿ¥ükûˆûýJÿ°àN²UÂ5Öÿôþ‚þ¢þ€ÿ³Œ¤·þŸüvúù=øo÷„÷øìøFúƒûöü²þ©ŒâvŽß'WC…Üÿ™ÿ¦ÿ¿ÿæÿaåÿzþüúçø™ø¯ø#ùÛù.úÛùIù+øÍöuõ˜ôLô?õÆö²øKúŽûˆü¦ýæþ0á+×¾)ÿGý·ûËúú ú{ú=û1üðüšýQþ}þÿÿDÿTÿ¤ÿ:_¿ª$Umã3Þ"ãþvýñü†ý›þàÿÃukA± ¿è< a èm-Ú6 f  g Ð r . 1 °˜Gíý ûaùùÝù?ûÝü£þ#·Éþ%ý ûú¥øÁ÷ì÷@ùóú‹üaý[ý¦üaûŽùY÷ŒõõàõA÷?ù•ûÑýèÿ°Võ[£sÄ… ž`"aáÇ.ûÿˆþÁýÎý þeþ8ÿÈÿ¶ÿµþ:ýÅû!ú˜ø¬÷^÷f÷É÷uøùSùÁù¹úÕûçü­ýtþ[ÿÊÿtÿµþÚý ýêüxýKþÿóÿw¡+ÄIÜ ÁT*„ÿJþºý‡ýÜýòþ@—£A÷‚¶ÿìûG*~K¬¶>Ó¹ ð Õ Þ ªÓÙá÷Ò8 Â È ò _ $ ýöa"ÿÇü³ûÈûÏüþ:ÿÔÿXþGüúñ÷ÉõÝópòò˜ò­óêôö®ö³öPö”õÝôBônôÐõ÷|øúvûÀüþ˜ÿõÁP:’`&ÙîñÄÊjŽÿÍýÙûú˜ùeú‹ûþüþëþñþ7þÍüûú*ú³úøûLýƒþ ÿ_þYý–üöû†û6ûpû%ü×ürýØýÔý%þýþAÜŽNo ) J B „ œžI”%õïŽÿ‡þ÷ýÒýËý¬ýµýãýÍýWþÒÿvH_Q,’Z¨õÙÔÒ©õž'ÍÞã < Ù ¢ K  -Ã}ÿOÿÞÿ]üÃJþ[û½ø@ö<ô”òÄñ¼ñÿñ òÒñYñØðPððÈïìï$ñ3óˆõ}ø-ûPýÎþúÿOŒÙض̋Zê· ÿ<ü!ù öÍõPöM÷Èø#ú,ûû‚ûñúú^ù7ùù¯úIüæýéþ#ÿÿ×þvþºýiüWûŸúÛù3ù™øCøøúüjþ û™ÈÐ E  Ž  6 ß D _ÛøcÁ•“‹vìHt]S‘Ü >üÃÚt è Z  [ (  N†˜qÚˆÿûZLÔ¤½faÿbþºþüÿ¢(f ~•#aýÅú)øÆõºó•òaò¤òêòôòúò–òßñÛð›ïÐî,ï½ð2ó:ösù\ü·þÌôY©,]ƒW 罄ði5ÿ³ükùKöôgôSõö¯÷•øÇømø±÷“öæõÉõ‰öNøuúÔüøþËÿßÿ‡ÿÿŒþÒý7ýìüVüœûúË÷ïõ2õõªöKøËúÃýØþ;× I Ë hÔ Ù ‹  «zטÚwJóU<E.@Õ † í A  ô 9ÿR8ÜpGï c G~·y,IjqÖ†Öÿ²ýðü‹ýCÿv¿‰&ãûMþ€úíöÏóVñÛï¶ï7ð¯ððäï.ïmî{íkì“ëåëVí}ï‰òúõ°ù‚üÿœÝ'W†Ä/ž v(ýÿÿ‡üÇùÁ÷.÷^÷ø™øéø·øø]÷¨öÕõ4õ]õVöÿ÷.úgüGþLÿíÿŸ×åÿóþ+þýÛû0úeøI÷ûöF÷øùíúøüÚþ p®àp B h  m ¾úŠ_u¥áJ§ÆÿÛþhþtÿ&1oÿ]  < Ò HÿD©Üè€å  …NUm€ „ Ç C ( Tæötÿþ+þ¹ÿ$Ê1È ¯B\PÿFü<ù—öõœô…ô,ô”óûò\òœñXðï³î8ïµðïònõ‰ø±ûþÓÿú`sÚ]‘Öÿ2ÿÕþ®þ8þþ›ýeü¯ùRöÀóóŒó‚ô«õ¿ö'÷ùöqö•õ{ôšóUó'ô’õ¯÷ZúpüÑýÿÞÿ‚’{ÿãþýýäü;ûùH÷Çö'÷ øaùAû9ý>ÿo§âÛè «âJøñΠ/úcÇ.­§ÆC rüöP s  ‡ N ³ ÈÿÐêȘɂ‹ »!¤ñϺ0 nxº$öü¦ú¨ù ú³ûæý\2ßؘþGüòùøèöÁöI÷‘÷ ÷@ö]õkô9óòñFòŽóÁõ™ø÷ûGÿ`}î¶°,u6dU¦êHÿ þ$û›÷¡ô@ó9óïóØô•õêõ‹õåô*ôlóðò÷òÄópõ—÷âùÄû¤ü0ýÊýTþšþfþ'þÛý(ý üFú»÷Ÿõ¸ôÓô›õW÷ãùÒüÏÿÊzÒ™ D å ðªc­ œÐê)‡ÄÌ—e¢; S r Æ ¥ ­  Ê Ù RŽ“‹˜Clþ ˆ Ô•? ´   ñï7­£ýûüù&úkû\ýžÿ’¡"‘SþËû)ù³ö¤ô„óCó½ó<ô\ô‡ôŒôô{óÉò‰òó]ôQöÑøßûêþÚo1x Å À L z®´/Á ÿûø÷vöËõöZööWöyõŸôÐó"óóWó“ô¦öëøxû#ýøý»þ‹ÿF£gVÿ_þ!ýû›ø¥ö•õ‹õ ö1÷6ù–û/þùgÍì <¾­÷46BÍÿiþ;ýSüÍûGûûêû¯þã ¤ ¡ 0 í ‰I3¼PÅ¥iQâI £ Ç ° f ’ T þ u ¿’2ÿü/û4ûüµý¬ÿl)Ÿþ´ûSùÒöôó€òcò:ò¯ñ.ñÜðÄð¾ðÑðñ óõÈ÷²ú€ý¨w!JòÝ¿E’<y¹+ÝZÌýú_÷÷õaõ‡õ¸õ„õöô!ô¦óPó÷ò½òó ôÏõ øƒúµü¢þCÁò“«‰çFU­ÿsýûƒúúçùwúêûÞý9ß9ˆP ý æ  ‘?ÁQçtÿÿžþ&ý8ûyùéø©úøýƒo¿‹ø } Ù !{6ño$ãÅB. ©×½’  Õ  æø*Ýÿ¸ü¥ú.ú&ûôü<ÿ x N‹-ÿ‚üºù÷ëôÁóxó£ó\ó„òuñnðŒï“îî²îfðâò.öÄùSýØXêÞU  a–¹#­n’5…|Þý&ú÷iö$ööÆõ÷ôóÒñ˜ðƒïÆîšî…ï’ñtôw÷Pú_üµý•þyÿ: ã™¸ÿ1þ*ü©ú+úcú¦úWûÍüÆþð‰Ðˆ    ³švÀ…AÙöEje!iþÓünüÏýÙ}I?aJî Ò ô .ùoPïžü“\D ü ™ ã æÑFðÿ üQúuùõùVûSýÿpõ Iÿ+ýæúqøöóó¿ò2ò¶ñúðôïÈîãí"í¸ì!í]îmð0ó<öNùeüžÿr—Ή¸  × þx¬î4‡Ñb€ÿæûìøw÷ ÷b÷…÷ùö­õ¾óÊñTð'ïfîîÊîðóÝõhøjú7ü±ýÿáÿ/´ÿÐþ þ ýƒûëùõø¶øØøùâùeû–ý‡´òü ž ý 3 Ö m7rô‰œ¯âQ:÷þSþgÿ]Ó+ « ê  ¢ h ¤ $Z¸_¥Öiw x À Ë ] ñ ó I K Û»ÊooýwûÚúmûÀü‘þG*ÔZÿ2ýÎúyø/öFô÷òMò'òÛñHñWðï¯í_ì²ëîëkíïiò£õ¹ø™û€þÜÉ`oùA‹¼HëŸé Ô¸¹¸üù&÷ÄöN÷Û÷Ç÷÷AõióêñÁð:ð^ðªñôîö¦ù³ûÊü®ýEþÂþÿùþÿ1ÿàþKþåüÀúœøf÷ëö ÷u÷˜ø<úgüâþ<ÙP¤£¾mæ ç_Âþ¥ýÔü*üûûãûOþ×V¸K I  ì JÔƒXÅ„NhH_Ðù ß }AìgG“•ô º ߤÍüÿ ÿÿÖÿ/¶›Bùýšûù£öõIôÑóó.òññïÊî“í«ìÎì&îCðíòÉõvø:ûÒý›ÿ(ìQÙ‘öͳÿ£Wü¥Í[ÿ<û!øuöÇõŒõ#õlôJóÜñîðMðþïøïœð òmô2÷äùþû‚ýÚþùha%ŸÒÿÒþrý»ûƒú>úšú#ûäûýŠþç&{u  Ò Üíÿ‚{˜íPêþÎýüDûú`údüÿFû ëìc ï õ 5ëÎ|RÄœ· ö —ná k µ o ° O ¼ ÂÁ˜®™È:Ðu6©ÿáü'úøùö¯ö–öýõ3õô¾òSñ¸ïÎî1ïtðúò3ö’ùAýs®c°.ûaéM¦0õ²h6$êþCûú÷Üõ÷ôíôXõ>õôóTñ¨ï.îììkìõìî)ñ5ôëöùÖúaü¾ýþÑþàþ’þæý ý³ûþù,ø÷ýöŒ÷Hø}ùû/ý¥ÿH®ñ>™ 7œ9¡N¥nÔÿÿPþ÷ücüGýÄÿü–0i: [ º DU„fQ'4¼éÓ } ™ØT‡TÜ Ÿƒùþïý$þkÿMˆÊSv†%šÿýŽú“øH÷—öêõ:õPô'óýñ¾ðâïHðAñsóoöyù‘ü‘ÿòÐi½R±"B² S!rɃýöù÷èõ·õ4öcö&ö$õôÞòÑññ¡ðñðòéóAö5øtùsúVû?üý¯ýþ‰þ~þ4þ…ýüÊùâ÷Èözöö2÷%ø}ù>ûvýuÿ¯y„wÊұĚmóîÿ’þYý%ü5ûÅùÛø?ù’ûÿ´Ð¢« º Ñ ô Xž)B³|O “ ‘  Ž ¬ e Í Ë B ú(i_ÿyþ¿þÕÿ”ð3}§çXl8Çþ¡üúúËùÏø¢÷övôËò)ñºïÓî/ïÃð^ó‡öãùÿüÄ·+JO›¹½åIÌ-"ÿœûZøöãôHôô‹óÎò§ñóð‘ð‚ð”ðñúñ®óÂõøïù`û™üðýÿþÜÿ@†[Ôÿÿàý+üLúùáøDùçùÙúÙû"ýïþíæó/`ŸyT–ðÃDÀ„ÿ!þ¼ü»ûÍúêù®ø?ø ùšûtþ¨(H:ˆ·ž ˜ GÆ\fº“… § Xwæ]§É²4á×e/²þWþµþ°ÿ7 ?ž+ ³Zåþ¡ýÆüSü)üÑû?ûUúù´÷ö¡ô.ôOôõÒ÷_ú7ýÍÿßAäÌR ¢â@ï;­C°ô¯ý÷ù ÷Sõßô·ôôôÅòñŸï9îƒíí•íïñsôI÷SùàúüHý?þÿ¿ÿc”tÉÿZþEü<úûø’ø„øáøÇù ûøüwÿû]X?ù晥qêV ­þ>ýØûCúløëö÷ùfüÍÿdüIûìøF º ‡ g9…ÇX|Ñu $߃֠1¤–Ó©„ÿòýMý~ý þÿ[¦&Ê–ÿˆýüÈúÐù^ù_ù^ùù„øÖ÷îöÜõ õæôšõËöüøºû½þv7¢‰Ý ’ o  N [oЙRü뼄Ôöýpú4ø÷Kö³õíô–óÖñð½îÔíGíníˆîxðóºõÇ÷.ùVú\û_ü$ý×ý‰þÿhÿ:ÿHþ¤üŽúùøyøþøúhûý;ÿfxt—®á÷7´~ƒÛÐþMý2ü+ûÞùŸøxøúfýï~ ïŽ[‘  $‹u ^Ŭ h ‡~Y¢"xbÙ7,©$ÿýØû¶ûJü1ý™þøÿ¨xrÿ¼ýþûiúèø·÷ ÷·ööKöàõdõ¬ôólò½ñÁñíòõ¼÷@û¦þ:´:6 g V ‰ × ‰µXPr[2æÛXÐÿ‹üúÄù¸ùÓùmùWørö}ô­òYñŠðWðÓð)ò?ô²öÑø…úäûýîýœþöþnÿÃÿÏÿÍÿ5ÿÅýñûªú]úŒú ûíûý`þ5Nz»;™ÅimúAoRqþŽü­úù ÷;õaô]õgøü8ÿy9}ó5x , 5ësêK 3 “ ¶æZ Ç é ¶ V jÿ@ôþ~ýý…ý€þ¯iVÿný¢û-ú+ù£øoø@ø—÷šö<õÚóœò+ñúï"ð7ñ-óíõzùµü7´ ½ _ Ò { wßÞÊZñb»þ=û ùNø6øfø<ø÷6õóTñ.ð‘ïwïðpñDó‘õ™÷8ùµú8ü’ý´þiÿ æ:†AèÿÏýõûþú½úýúÆûÝüHþ%|ÞEï‘ ÿÜÊÊÃnô'ˆ¢Ôþ2ýrûRùÇ÷÷÷Oú}ýŒµöŸ†¿i — ë ½Uµqõù ¡ oî@F¢õã|:Ó¥¹Z+þÊü8üKüîüþ¨ÿî5°‡ÿæýDü»ú]ùø;ø,øÄ÷÷ö“ô^óïñzð)ðÍðcò@õøVû¥þFTø P É  Ï Ü @ áÁ»…lÒ,çÿÞûðùOùÝø,øðö5õþòñ’ïÙîàîuï¾ðbòyô¡ölø!ú€ûÈüþÏþGÿÁÿ F)ûþ ý×úHù§øÒø‡ùÖú<üÀý†ÿš±¼ ª„iM/ýD^×y6ÿüýƒüûÄú>ü>ÿŽ%áÍ‘ ò ÿ œ n.œ¢Æ4rJ¦ð C & à ª “ B ¤Üòc4o·ý­ûxú0ú¹úÓû€ý/ÿçÿ„ÿ<þQüEúkø¸ö‰õõõõ²ôéóÍò·ñhð¯îàíeîÎïTògõÒøfüCÀ£ > = ô D ˜Z(ke°ºïZã‰þkü~û6û°ú×ù*øýõ¥óÿñíðšðØðÛñ]óõê÷èù±ûgýÅþÎ 6PH-nÊþºüúúúÆù ú«úƒûpü½ýSÿ&÷;¸m´Xññ ¸< òþêýrüiúNù ú¢üöÿþQù( G à ¼…ø% Dp>^C ` 0 ½ Ü Z î 1  ¯ « ±Ó¿<ÿÂýKý«ý¡þ+ìáà¾ÿ”ý…û­ùbø·÷p÷;÷§ö©õôJòÎð ïÖí·í î ð[ó•ö†ùpüÿÀ<¥ÌêÜÚKÏÀ¸æLQÊÍÿ³üuú­ù¼ùðùÚùóø>÷3õJóÛñ)ñæð[ñtòAômötø0úÝûmýæþ÷ÿ”ß!<‰eCnþÂüÖû¾ûüÐüÜý0ÿÑØÆ”Ÿ¸—<ê¤Ã´qÍ›nÿƒþæýòü’û…ú û™ýù4EeèNÀ\  F eg}`ŒB8Ð e ¤æóIÀ Ñ`ɨþ8ýãü]ýeþ¿ÿ684#Fÿ6ýRûËùÉø\øXøiø*ø÷iö©ôÜòXñüïvï ðáñÏô/øcûœþ딢᳷pspsÀ^öž…¬þ4û£øµ÷Ô÷Zøø ø¶öÁôäòjñ¡ð’ðñ òÄóñõøøùäûŽýïþÝÿ(ÇÿÇÿÅÿúþ`ý›û­úúôúºûçüCþ'Sˆ„ùV—µ®ã^£kþôü½ûkúèøÐ÷DøÐú¢þ‰_L]= í ¾ ¡ 1 ޵Ux¸Œä Z þ + ì Æ “ K ÒI’@Në}ÿ—ýÏüåü¸ý&ÿ­n)$òýÇûúëøQø÷÷Æ÷f÷Àötõô€òñIððñ€ózöú{ý6Ü¢ž ™ µ E « G6…K×X „Äðÿ„üøùËø¦øçøÚøø;öÔóŠñÐïïï®ïñ´òô…öøþùÌûqýºþqÿ¶ÿ›ÿ$ÿ°þþ¤üªú¥øz÷v÷Tø¬ùSûýÿE Çže521%„{jTõC«þ#ý£ûœù ø'ø úšý&ðÏAf• Ö V =Q"7ô-e:˜Ý m …  ¯  U ‘ ßn:ŠÀÿŸýzü@ü§üžýDÿÅa%éÿùýûû0ú±øÖ÷…÷z÷÷iöEõ²ó ò)ðsîúípîïò|õ ù©üMqX ¬ » K pØN–è–ujý úÁùªùàùúÃù¸øÕöÜô.ó"òŽñÔñÄòxô‰öµø‘ú\ü;þêÿ; U©¸µ•Žuÿïüèú—ùùlùRú}ûýÝþ«2‘²dHâ$Èþ ý~û-úÜøP÷Óõ°õ˜÷úú¯þ©À(ãàJ f ¾ ÂVZN¥øô ´ ù â  i › J § Í \=Òƒ±ÿžþHþ|þeÿÉ¥°|þxü¾úžùùøGøøg÷[öõó.ñð¶ïôðQó0ö±ùýWŽ* ¹ õ - ÿÚÄùóƒJ|wFÿPü–ú0ú€úÔú‰úù²ö¸óvðåíIì/ì/íïwñ0ôeöiø-úÊûdýêþ <$ÇM‚Ê>…ÿRþ²ýŸýþ&ÿm¹ÿ=‡‹Lœº•l\ƒÿÌýüFúò÷Jöö«÷€útý>0Üõ¯ ¦ š Å«¼ž ] Ø o }"< r É Ñ š ñ˜ƒÿ´ÿþ¿ýíýãþ‹+ æÎúýüŸúôùnùæø‰øÑ÷¥ö_õôó§òÔñšñ(òÀóSösùýäeq— ~ ? g $‹®%uQ†TMyðý“üFü®üíüfüÎúkøWõÛñÞîýìuìí%îÌï ñ*ó¹ôžöÅøû÷üŠþšÿJÄ,pÐÝÿåþ0þõýNþóþÈÿÆß;ÚƒÂfOÎ!Œ…˺$LLþ<ü,ú(ø÷@÷äøNû©ýàÿØÆ‰CèØ ' V믖†l j y ÉŽ®¾ŸÂ1ƒYaµ›þý^üüRü"ýhþ®ÿ‚À<'ÿàý¡üÍû¦ûèûü¹û5ú^ø›ö‡ôþò2ò—ñHòìóaö{ùšüòÿ†P Î&ªÉõA‰1 ZÂæÖ ?ÕÝÿ5þÔûÀø³õ8ómñ ðùîgîCî`î:ïÃðÿò‘õ ølú]üÂý´þêþÁþ—þÓþbÿÖÿÍÿ€ÿÿµþ´þ)ÿÑÿÂà$˜¿$ G Ý ¼  9(£Æý¥ú4ø÷æöv÷øÉøúçûþ§›¶ 6 ‹êY{—9« V q ú v ¨‘ ˜ºõüê$¡ÿVÿ3ÿÿ­þ‚þMþÌýÛü¦û†úÃùtùÂù3úûðûrüyü+üMû5úèøß÷ÄöÞõvõšõFö6÷=øRù¥ú6ü­ý&ÿžkçì—? Èú™–c¼sÜý‚û¼ùø~öîô1óåðîÜì#ìyìòíCð7óOö ù û6üSü,üuü7ýqþðÿzñËìîL’á~ Ì œ ¢ Ó c †üØ¥þ!üûÿúûËútúcúû<üñýª~d /” h Î ÄRD8øg® ³Ù[}ÂþÁýˆýîýˆþÿƒÿ¤ÿÿnýEûèøêö¦õõõæõ÷eøsù3ú®úÛúû$û”û5üuükü*üKûðùÛø>øø„øùû™üøý]ÿ­—ªç0Š? ñ Ñ îç}þ¦ò,åÿeþGü¨ùÝötôqò6ñ¶ðØð‘ñ±òïóbõBö¹öe÷uøÉùWû)ýìþAeƒ§í5Aª¡£ê^/   ? + • è krïÿýaûNú{ùªø_øÜøûùÂûþ­J; ¢ Q#7íÀ x Ë ÿçY®bŸùüÇÿ‰þ¾ý¿ýþ¾ÿ'UþÑZêþãû±øö¹ôgô¬ôÿôãõßö0÷;÷%÷÷c÷¿÷\øLù~ú•û2üÍûàúèù¸øÍ÷¢÷bø ùÅùÀúØûšüÆüývþ‰*gŸ ¢ y £§ë޶¯%CÐþý-û~ù¤÷ö,õõŠõjö]÷È÷“÷9÷Ìö•ö¿ö’÷áø‡úDüþÕÿÔÆÄÅÚ@ û ’ ó°½{ i ,àsÿÖþ#þ ýÿûcûû­ûÔü—þ.óp…0 ' © ú À S  í ± r ÚíÒ|yÅ6ÿQþBþÿYvMЃþoûø>õ-óCòJòÑòôòõ3÷ø®ø¿ø»ø³øù›ù’ú ûVûžú@ùh÷iõó’òèòŸó‚ôõÓö€÷¥÷8øÞùÿüÚ‚ = ~Fì…‘áÕ0€PÆ ÿÎý’üü üüýËüéûäúïùFùù¥ù„úGûüMýnþïÿp]¨òÀ U @ODwxÝ Á „Hûûƒþÿÿàý#ýÄü7ý^þ#—=’ À •  ³D®äiî4åÝ‘tOÚ/ÿüþßÿnNìâÕoÑ)ÿû©÷9õóóóôÕõêöÃ÷‡øìø%ùVùÊùiú*ûû¹ûíú@ù6÷çô(ó7òcòÑòóxó×óŒóÐò(óøôvøÅüù££—:ÿ”þ%þÐý™ýÕýþþgþ§þþþ–ýýþðþ6CV× ÿeþãýÆýÄýÌý4þËþkÿZµ L²’ï È E+H¥bËó¤¸  °E±(u#ÿýþ•ÿ1†å÷\ µ e ¾Ï\Õ¦V˜Ç¡ç¸šµÿÖþÀýÄüdüàü-þçÿ¯<jÊsÜMýßù,÷iõ@ô‹ó ô·õ9÷{ø\ù7úUû5üŽýÔþ®ÿlÍ›þ-ü!ùdöIôZóªò.ò ò9òò?ññdòƒõ)ùïüô”ùˆÚþýÝüWü¶û9ûÙúŠúúàùâùúÏù0ùÁøëø¡ù6ûÀüˆýÊýéýÓýÏý¿ýïýaþìþšÿv+ÜÚV(Äù¦ ÷ »ÏæˆÄ 4î\r› ãZSO/  ``E~bu  ë‹Þƒ ýj’¸ÿêýüjúùúÄûþ6±ÎqHaþ–ú÷Jô+òÃð ðëïñòÏò­óÍôUödøÖúýÓþ=Ó`óþžüÃùK÷Èõ–õÝõ8öàö<÷Ôöõ”ôíôäö¤ùÙü«ÿÀºWÅÍþâü€ûúýùâù7ú‰ú†ú¦ú½ú¶úQúzùÉø„øàø4útûôû×û©û†ûxûsûÁûLü²ü,ýÈýuþzÿ©Ë’Iigå  Å òX\PØ € VÓÁù Q±N¤| 5 ƒ"ó-3Ì^ q ý ˜ Ü Ú gÃ+Q ¨þèü^üýSþÓÿ ‡ h:–ü3ùVöéóÕñBñëñžò_óÚó;ôFõ…öQødú5üØýýþçþ)þGü½ù[÷LõDôjóžòJò<ò§ñºðuðóñlõ}ù¢ý«§¦ÿ\ý—û_úUùÄøÄø÷øõø%ùùúTú ú¹ùµùþùûRüùüýáü¸üŒüRüBü\ülü©ü*ýÕýîþ,j+¶ì» b ŽÓùŸ¾›Ç à ÁÚ#ABÝ’„Ov€Û”  %½Q*x < { v ø È R hÙöÈÿDýXûâúìûÙýØs"Ä /{ýÿùÏö)ôXò@ññ•òÑòió ôÏôödø¤úý8ÿÛW>Éÿzýùúšøèö¥õ¾ô2ôô¡ó=ó!ósôM÷›ú-þDŸìõçþ ý‡û=úbùïø¤øøÂøäøÝøyøFø©ø¥ùfû`ý¡þ-ÿ÷þmþŒýÝü?üäûŸûKûû7û–û$ü ýêýòþ,YtP a ø Bµ Ù ‚ f 2êÔ4—¨¹ ïëäB ã (mFy]ZË — õ %£ P t |/V+ýCü¨ü-þ.³ ¦ÿA\íüÓù-÷õ›óºò§òÍò§òtòOò¢òžóuõà÷‹úýðþ€ÿãþIýöúï÷õHógòÏñÐñÿñÃñ ñ‰ðñOó~önúxþÐûÈ4•¢eþ…ü¨úvùþøù|ùNú\ûrüýóüÜü·üýþoÿFz ¶ {ºÐßÖê(¡'‘¸Éý¹®  è  Ø ?   # ÃTõNo„÷ƒØ”( q »£3V &  h 6  r ª 3M…øAmÿþ´ýÕþ„–]íâ µ Jo–þ`ûMøyõ¬óó–òhòpòXòáò6ô6öÏøqû\ý¸þ ÿ6þcü úd÷&õóó`óó óÜò-òíðƒðUñôi÷QûÚþÒ<Nè›ÿêü²úäøš÷éö÷’÷AøÕø2ùÿøMøJ÷~ö#ö¹önø°ú‹üÌýÇþŒÿùÿcŒÓT¬a;<ûÎä| . ±©Ü.ùƒq|z Ÿ µõ·k¸é IÏè£Nr¯ ² 2 É æ È + > g ë Á ‹ Þ S1åü:þ³ûßùFùúèûþñÿלî)ä>ÿüìùq÷ÓõQõyõgõ‹õõ{õÒõ)ö*÷ÈøLúõûüÍü\ü5ûfù‰÷§õRôúòÕñ9ñ¶ððíï×ð6óËö¦ú\þ{êàŸõ&þüAú´ø‹÷íö¯öîöi÷§÷h÷.÷7÷S÷YøûùTû)üƒü¼üÆüçü/ýmý²ýþ.þXþÉþtÿ ¾d-‡Fº— 3 +^xšŠq â Ú7óâ™6Õ±íÞT >  ŸåÆ9² ¸ 2 > · ·  Æ :„”Ìmþ¿û{úûóü5ÿŠÖª’éÃÛÎýðúnø˜ö£õ¥õêõóõ¤õ1õŽôRôÀôöø6úTü­ýþsýÆûNù”ö}ôåòbñOðdï`îí^ìÔìï!òØõdù²ü>ÿÖ)°œÿJþÝü4û‰ù.ø ÷iöböÑö—÷ø)øYøwøáøìù(ûüªüýšý4þÿáÿ†³9mÿºþvþ®þÿÄÿµø“¸?ç á :BŒ † ¶ mãIJ?‹!} ¡ û € ë é7 Ú]‰¯ P 7 J R ¢    Ÿ»ÿÞü ûÈúÿûñýÁÿihd€Øý˜ûÆùCøY÷ ÷ù÷ì÷Ð÷Ÿ÷”÷ï÷ŽøÛùÓû•ýÿèÿÔÿâþ3ý¹ú‡ø÷ïõ´ô—ó6ògð[î^íðílðøóå÷ÂûSÿ‚F·?eþrü6ú+ø^öõvôbô§ôcõöö‘õõ¤ôìôþõ†÷òøúçú»ûhüý‹ýàýüý¿ýƒýŽý'þAÿUbMR•.] U Ó Šž:\ Z nee¸4‘·àtÞ0ÍØZ- å ¢ .ŠË rûÂÛ¬å W i z´j€ÐþBýKý§þb ¶==rY!f¬ýLûÑø/÷wöPö™ößöuöwöRö¦ö©÷]ù"ûýÿ^¯€þyü²ú—ù[øP÷4ö·ôõòEñ­ðýñêôwø"ü„ÿþø•\èÿgþKý/üèú¨ù¹ø¿÷÷ÄöâöÒöŒööüõ¦õÓõ¥ö½÷.øqøÈø0ù ùNúÝúTûlûZû4û]ûœûJüþü»ý¹þ,Îíµ Á ç h u æ ŽT8QðéÙ,~yR ™ é Ú 9&» > Ñ Î « ¤n Û 7 ,€´dpÿÜÿQáûq«•)FÿyýÁûQúxùýøÁøTøÑ÷ª÷Â÷#øù‰úüdýÔþ›ÿ“ÿ‹þküIúSø0÷öñômó5òÊðSïïwð«óý÷üŸoçÍf±æÿþ•ý—üLû<ú<ùSø¿÷…÷”÷x÷Y÷•÷þ÷¶øÎùîúJû5ûIûûü²üNý™ýjýåü\üÀûû¾û\üý-þËÿóÜÿ†  ® † Ô  ï 9ÆØ“oL­dªó&¼ºu ¹ ¬ "  ¾ u ú † H ° p Ð 3 Í 4 ‚YQþ³ýCþ™ÿ8 ì&7aè.¦_ÿþáüiüiü0üÌûûiú*úúsúÓû6ýÿþ‘uZ§Çþ´üûèùìøë÷´öHõ[ómñpð-ñÃót÷{û ÿßp ê©UÿØýxüûÄùÒøÿ÷Æ÷ð÷$øø«÷Œ÷·÷\ø›ùíú·ûügü¢üÎüáüãüüûûUûýúÉúûõûýLþ¦ÿ(–Ib ü — Š  x F Z¹ŽyNÃ<|ùZ™úqGKB ò ´ ' p « ª b  ç  :  d ( ç§ú­ýýýNýjþãÿHÏk—Êòb ¶þ]üú¤øøø‹ø’ø¨ø6ù—ùqúßûý‚ÿwöÒŸoH þüúDùå÷…öõsóAò‚òÃôøGý«dÄ€˜†QH‹ÿõý^üûÄùŸø¥÷ ÷÷D÷<÷÷!÷s÷;ø:ù!úqúTú6ú.úLú¾ú9ûËûü&ü/ü_üÜü¸ý°þpÿÿ]O£‘Ü X ? Ê ? +VUŽ¥©æH„»·Î>:¶PÝd Þ ß s ³ q ñ Z c t + H  ±õÿþwýCþÀÿŽDÿ ®«°É‘•ý¬û.úùÝø¤ø`øø‘÷B÷²÷›ø÷ùKû£ü þùþÿþ)þ­üûÜù%ùmøŠ÷söõ¸ó(ò¼ñóUöúãþO QtÓ/µÜ‹ÿþ¥ü-û@úáùÛùÁù¤ù©ùàù8úÕúaû]ûøúûúûZû¼û+üeüuüü©ûHû?ûÞûøüþ1ÿnEÏãU  ¼ F 6 „œ­†êÞεÉÍѬÒ4Ž›þR P ÿ“d¢e ï ! – u+ѵhÿ½ýý–ý›þÒÿyõ1¥‘‡XÿoýÂûÆúAú)úÂú ûûúÔú©ú#ûü ý\þêÿ‰´”M\ÿûüæúaùø÷öõõ)ô%óŸò‰óöúþ3XŠ…i¿`Ÿÿ2ÿˆþÃýýˆüüÓûÔû3üCü²ûøúúUúŠú¢únú úÊùøù>ú¿ú€û4ü˜ü®üœüYüüqüNý#þðþÙÿ;"‚êÒ § Á  ¯ 8 B1]!_Ѽ Œáƒ¬i>¤¡ a Å À l µ ðu4ÉçÊÌxæÿ>þÜü7ü€ülý þßÿ0®"AæÿDýùúÚø4÷yöLö:öÛö÷½÷kø=ù`úü¤ý†ÿæúLÿÿ\þ®ü]û>úùù÷Ùöûõ%õõ'ö$ùý"€®­Ï–ÿºþIþ¦ý-ý¼üpüüÆû°û˜ûZûYûâûÖüÖýgþnþ¾ýñü>üÛû©ûÂûûûøû¬ûcû?ûrûüóüÛýÞþñÿmhÀˆ I F î 8 ™‚xBuZ)É=²7[Nµ{M(± Ò 9 ¿ ß § • Í á ƒ d ‚ FñcÔÿeýªûñú/û6ü¸ý:ÿÈnð¦dñ£÷ý5ûïøx÷wöÓõ‚õuõiõRõiõ•õ€ö¹÷‚ù×û»ýÿ·ÿ1ÿÃýÊû{ù4÷Ñõõ‡ôQô€ô¾ôõ£õ®ö"ùýüã6Kún ëÇïþÍýVýOýoý¸ýúýéýxý ýqüàû£ûöûÞüÈý~þ¸þxþêýý…ýÀýBþïþ/ÿÿíþÿlÿAHmzvå‰. f û × Z £ Ž òñô}Bß =¯ÿjÿ«ÿtÞ¯ÞŠ ¹ ³  YѺݺü¥ù2˜ÿÁýÈüü ýþLÿ‡ÁIð¡SUþFûÐø:÷Xöxõtõ¦öV÷!ø¶øFùUú@ûóûýóý¿þÁþ×ý.üú¼÷Äõ‡ôô!ô¬ôZõ ögöÀö„÷TùiüÅÿ¼º|¿0 õþ_ýDüôûüeü¤üàü“üØûàúùù!ù›øàø¼ùçú¿ûëûŸûïúMú'úxúûÌûiüÔü6ýÅývþÿœ³¡\i ‘ ¶ ‹š3ŠÅ{Ž ­ 4 >e.­³±N³^´ # †ñ× | C 8 ò2:gÿøý¥ü~ûýú"ûüEý¼þa%µªdÊ;ßüLùDöô:ó§òšò^óVôFõ=ößöš÷’ø\ù%ú~ûaüâü¤üœûâùq÷õjózò@òòdó~ôÚõôö´÷ù¹ûQÿ Î‡lÀd°Mhÿ(ÿ)ÿ ÿÚþ“þêýáü±ûÏúúzùXù¹ùJúÄúûüú¥úDúHú•úû¢ûôûüAüÌü¨ý›þËÿîÌ"~4¿åh v õ ÷ ”¨?[ í  ŽØu*ñj¶Ö¡z ü ÓÌÎ 8 T ¢ QÀ*”#Àzÿ—þHþÐþøÿš=µÙzEn$þÀú’÷$õŒóÌòiòsòOó‚ô§õÐö"øbùVúûúûÅüQý¶üBûZùâöeôNòóð¿ð ññò£ó7ô°ô¾õÀ÷ûþl³Éò õþSýQüüü:ü‚üýeýÀýþ#þøýFý™üMüðû«û»û¥ûHûûùúûXû‚û¥û´ûÈû6ü+ý€þõÿG@¨ý‹æ< D /ÆÞˆi¶  ]V"™ÓÔækÏæŸÇ)} ™ ,¬½ z a ¯ W æ / õnß}+å×ÿUÿÅÿÞ¬d†âÿaü*ùèöhõWôÄóÏó@ôXõBö3÷?ø?ùóùòúPüýÄýÀý§üûÉø,ö*ô+óÛòâò!óµó3ôRôVôùô÷júáý®\Ó5…Rþ+üßúOúúàùèùúFúœúqúOúÇù ùPøOøÃøbùKúûGû ûû[û¢ûüœü/ýŸýþ®þ9ÿªÿ#%Ñÿ¯ÿf:-¦é [ûù-õ \ ¹ …0kõ‡‚õO[5”ù  é gy \ §ß†vT­Ž\ÌY>ÿöþý…ºv‘ Ì  8.†·üUùÃöÖô•ó$ó]óôéô¥õ@ö.÷ øDù•úÑûÕüFýý&üúe÷ýôCómòVò”ò;ó«óÄóóô¸õ¹ø9üÿw¨g~hþœüûûãúÜúûUû•û¼ûûûãûûùù;ùÏøÍørù#úcúNúfúŒú´úûÛû‹ü ýýôýOþ¬þÿPÿlÿÝÿØ£EkX  –Ù¸E´ u [ @àe-šœ¾Á+^ d 2x Ä»  гmi×Y®òþýÒûÄû*ýÊÿ뮺 ± O ½ÑBíýûôø.÷ìõýõöÚöýöG÷£÷_ø‰ù ûUü›ýwþ—þEþôü©úÏ÷¿õ@ô3ó´òsòOòüñýðpð¤ñ(ôE÷ÅúVþ”ë˜xUèþ¼üÑúmùƒø=øcøÂømù`ú&ûsûdû3ûÌú’úðú´ûCüzü¹üøüý>ýŠý±ýðýþ;þpþŸþ¥þþ;þþJþMÿ?âÑ~ Ó k ,~`‡ ¾ š õFØ8oÞn7˜¦^Q 3 ³ Ø Jsa  R ó Y ¹ðÀQµXQþ#ü²ú¨ú5üþþ½èqB Óæe¦õþFübúÍøøVøPøMøNø£÷”÷ømù×ú—üBþ¦ÿˆ_*ÿNýû†ù²÷IöõœóåñÓïŒîïâð\ó?ö«ùîüêÿ“µÉBÿ€ýÕûiúù,ø—÷%÷÷=÷÷¬÷Ç÷ øZø¢øQùJúÛú#ûû$üÛü±ý±þ‹ÿ)W>¾ÿ.ÿ“þïýaý~ýNþn[ ¤ ¤ î  í # ¯ ø,-(ãuÿ±“Öztú  Q n ³i» ² ì • X Þ ú £¦¶šGþÇûóùlùVúWüÙþ<a Ü ×âÿþüGûUúÙù¸ùlùåø[ø©÷ûößöd÷–øú ûküŽýÅýŽý:ý|üÖûû¼ù&øéõâòiðîïEñóCöù&üÿ+þ»ÄzÿþÞü£ûú{ùGøQ÷ãö¹ö‰övö}ö¾ö÷å÷Ùøuùÿù±ú#ûÅûÏüçýçþÝÿvÌd®ÿùþ þøüAü0ü ý]ÿ4-ÔÁ ! g > ™ gÏáB’—9&N´p¬ 2 „ ’ |ëgá - J Ï Ê 2 • Q Þ ðÌ…5íÿ¿ýüBûÄû'ýØþ©±ƒžÀï£P¥ÖþÛýuýãü—üü¶û·úeùVøÿ÷ó÷ øí÷¹øÒùõúû˜üJýýýÜýzý$üùîõ`òzðkðjñ óôô÷mùœû{ýÐþ¡ÿíÿ½ÿIÿTþüüfû°ù øÂöÛõmõ.õ+õ„õ/ö&÷8ø=ùDúOû(üýñýÑþ UTNý=Ìÿþmý“üÊü?þ¢X|-ta€WÈ+çŒþs½¯ ¤ 0 (   h ß  $ · z t ø » ¯ ù Õm½Ðÿ6ýÀûÜûýeþƒÿy D?ƒlÿ|þBýüü¥ýÌþro°µwþ­üûù½ø9ø;øÚøúeû²üíý‰þþëûù‚öaõrõöÄöW÷õ÷¶ø±ùÃúÑûÁüÃýËþ£ÿ%ÿ•ý‚û°ùGøÕöªõõôô¡ôÔô¿ô}ô‹ôðôÚõóö8øÓùÁûÉýùJÖ‡KÇwÿìþsÿ㊗oÇÖÁ{Ç“`­p%·1ë° Ì¯•$ x j Ö Ç Š  ‹ 7 ž ¾ ¸b1 _ # àmúÚÿŸþ„þiÿ¼  z%Uøý†ûqù0ømø5ùŠúWüýý°ÿ²/Û4þ%üßù,ø}ö:õ×ô[õ—ö@ødúü®üü†úCùù…ùiúãúáútúæùuùù¬øÑønù—úØûEýsþÿÿÒþ]þÓý ýžüˆü~üfüBüÈûÖúÙùùÊøùùŽúÎû!ý¸þb¾s­ˆ‚ÿÿ©ÿC)™ŒJ,JH*-   ewÍ€Ûª«ØÜ¿o»p{²+Œ¸WŸ w p˜ˆn×þQþëþqR ›9zÙFKýkú~øÔ÷Û÷¢ørúèü9ÿž8Ç¡ÛýûQùÇ÷Ûö¥ö ÷û÷ùŸù%ù¿÷Úö8÷Tøôù®ûøüŠý[ý¡ü…ûyúÒùœù ùñùuúJûÀûøûü@ünü†üüÃü)ý³ýþ þZý…üÆûlûgûÞû°ü‡ýQþÿõÿÝÈT#¦5%ׂlÊvÀš-˜æ¤"Ê*qЦÔ?!9›Åœ#L©ÙQÑ$1’¾Y  åk•VäÿÁý™ü»üëý­ÿEŽ¢tg8*¬þÓüûù ø¸÷î÷&ùÚúÙü)ÿªHM©GÿdýÁûú¾ù ùkø©øxøÌ÷ãöcöËöü÷¦ùNûéü5þ›þRþãý6ý†üâûûdúÞù«ùwùùˆøDøoøÔøtù™ú½ûÆüÇýYþhþ0þôýçýþwþ ÿ¯ÿ0“pØ( Roìÿ<§æÒ æ þ ½ þ~BøëòŸmó¯ùŸý ß  ¢ ¸”¦7Á @Ô–Ê‹(áÌþ‰þMÿŸô6†Í7‡ö~Oÿý_û,úaùù(ùÖùçúÍûÊü^ý°ýý¬ü+ûþùUù;ù%ùgùÖùú»ùªø§÷q÷"ø*ùQú™ûËüŒý¹ývýôü±ü|üüVûÁúFúÖù9ùeø•÷ýö–ö”ö ÷£÷Qøðø¤ù-úˆúûü6ý>þEÿ'Ó²ˆ5¾0ïüÈݧ|H­6 / = ¾ V  eš<A"I]<8rk 3 » È ´  Ç ÀpÇuQ–•—­ÿ¥ýêûÓúÐúü0þG+ë¼6 3¯þ^üAúîø`øî÷ øñø·ù§úÀûÉüÝýþúýüOûWúSùø÷÷Pö“õÂô`ôÊôNöø±ùîúüý°ýàý·ý¨ýþ•þ×þÄþ«þþ/þjýwü}ûŠúŸù ù/ùùMúû–û¢û ûÑû}ümýˆþ‹ÿWëÝæÌ:³ø¶vÃûY¶¶zr ®  ŸùℲ « ¨àÆ\$­èÞ? 0 ! àP3½½– ­  ´üøñþŒüûú²ú·ûFý¦þH@ïéÐrÑÿlþœýÜü?ü+üUüãüsýüýþ4ÿ=ÿæþþiýÔü üIû™úZù÷›õkô„ôwõ­öÿ÷wùûMüõü?ýý«üJüÔû@ûÓú¶ú¹ú›úPú ú²ùðøøŠ÷–÷7ø)ù ú·ú û¦ûˆü¬ýÞþÊùòô9Úœ Ô*¿Ñ½]T‹w Œ  ó á >ÕLáó”{èÒ4AÁos\ § ž g ­™ìê{I™×1zå)þLüwûèûýZþ¤ÿfa&P¹œ(`ÿ/ýüû?úôùHú’úÞúŸúpú˜úƒúÐù€ùÛù:ú”úíú/û£ú!ù|÷wööÌ÷5ùBú ûòûýÚýþ»ýŒý×ý1þþÆý”ý?ýˆüÌûû5ú6ùø†÷o÷˜÷ø÷2øøé÷øÞøqúµüEÿT|ÎÞÎExáö ÑSšÝ,J7= I n Œ kå‘„û2´¼í|E,É<NÓ ™ã»×iæE¯ ²ýßû1ûÂûÛüIþÏÿ¤pÏ7õc‹›Úÿ ÿxþ þAý†ü¢ûtúÈùrùÖøIø~øõøÅù’úûêúÀùÏ÷äõâôõöS÷ ø„øù™ù¢ùfù+ù^ùúöúuû¤ûÁû­ûyû¤ûü#üíû˜û^û4ûéú•úúù‚øqøAùûBýrÿè[#Ÿ[š#€næGN˜Œsej£H ‰ 7  æ  d N W Å ý±ã†â|?ñwŽjjYènqуù‹Rk>üþµüTú¢øì÷ øoøBù˜ú\üaþ¦ÿƒÿ•þDý—ü÷ü]ýÛý\þ4þ¨ýŠü ûú)ùøƒ÷â÷8ù»ú%üWý7ý˜ûßøüö~ö;÷¬øúûüüü.ýÑüSüüWüý´ýÒý‚ý*ýkü°ûxû®ûŽû3ûöú'û]û¦û©û!ûEú³ù¥ù•údüÀþʦߴÆÂ|Õð2ØX1¿èZäÍÁho h£+±¾Pm ?Q  < d ™ a A  Ö { h u Ë Ã±¨_Øþ üLû×úÛú-ûýûÚý®ÿOÕ%—y±þý0ü+üIüòüòü ýeü‰û¥ú§ùfø<÷·öÆö˜÷ƒøÃù'ú˜ùÀ÷özõdöø÷Óùû>üýtýöüDüÚû"ü‘üèü¾üü"ûúÍøSøbøîøbù¤ù$úÖúlû·ûŠûÊú ú”ùÿùhû ýîÿoßÚ+”$š˜0GÝÀ£žÊ1äæË  ¡ n ] r  ùy`Ô¶7 ðé¥:r“›ck ó¦ $ - ð° ãÿOþ_ýâütü6üÌüíý{ÿ÷ÿ]ÿXþlüËúÞùêù•úŒûüOüüûRùï÷­öõ¿ôØôoõŒö¼÷ÛøÓøÐ÷yö³õö„÷ù¶úüAýþ,þÈý8ýuýnþhÿçÿ°ÿÁþqýåûÁú/úlú¿úûkû×û>üžü¢ü#ü;ûfúúúÈû¸ýEÿ3ŽÒ'Ò Ü!ëÓ):xçbmw¶ëvÄmŒÎ;±j„¶4˜©ZàÎ-s0 2 q ¾ N ½%I!²§þ‘ý5ý"ýqý•þ+(;„¥ÊÐsþ½üüœûqûoûMûÄú¨ù¯÷Qöõ–ó®òªò;óüóõö‰öwõ³ónòò¥ó)õöøVùƒúÎú†úôùúÓúüý‹ýˆý0ýCü?û·ú‘ú„úEúíù!úŒúû¨ûñû ü3ütü,ýjþ(kTVB7³‡Rµ¹¹Zõ ‰ Ä  0 7 Q º ; T H [ V ß ž‘”ÉUW¡ G’l ¼‚„] @ ~ Ö †çIŸŽôþ£ü&û]úÕùêùWúÃû—ýèþÄÿ\ñÿøþýjü2üGü„üîüÆüLüIûNùõ÷ŒöYõ¨ô«ô6õNö…÷»øÏøˆ÷ÛõÃôÏôÆõ÷OøFùúlú%úùìø´ø”ùû—ü±ý þ«ýxü<ûeúú*ú/ú5úªúûwûmûÝúúqùùùû9ýÿW8[•é5?êLç;ñ’þG ¬ í W , ò J ¬ ç d  t3oLnö´o÷Sœ‹I» ¥ Å ô + ©  ˜,u<‰þ”ýÍümü ý*þŸÿ}¶ÐæT2ÿkþìý‘ýIýÆü"ü®ú°ø¶öÆôÔò>ñ™ð­ðñ"ò‹ó÷óó‡ñ_ðŒðÁñŠó|õW÷ùzú÷úêúŽú]úøúØû±ü.ý6ý}ü&û¦ùºøBø<øWøxøÎøFù¯ùåùúùæùúwú‹û¢ýÙÿëéèSÀºHÛ5/=Ã)»«N ª 5 «  ì Ù X  æ È Ï C ÷ áEåì‰}˜Òòßèîϡ  z¨µ$Qü,ÿþâüüßûÀüòýÿýÿ†oƒÿHþ¥ýÀý5þ{þ!ÿ§ÿŽÿœþ»üòúùŸö‰ôfó¨óô7õZöÙöõÚóhòòzò¥óñôNöL÷ø@øû÷`÷÷‡÷ˆø¬ù\ú¡úgúóù/ùíø$ùhù½ùú‘úûUûcû&ûûúúû ü×ýÅÿ³Ÿ§ ¢½êîñáuîÊ*º‹D × Ä › õ ,  i à ½ Ÿ Î0çé>–4 ö À s â 7 >  :  :'bè  B ‡™¯ÿþtý<ýeýŽþªÿP¸ìtaÿõýÒüÇü`ý¥ýÅýUý§ü_ûÕùVø öÂô[óÜò(óôÿôCöÏöñõpô˜óœó›ôö÷·÷0øcøà÷±örõøô•õ÷Gø&ù·ù‹ù{ø@÷/ö®õ‰õõÆõLö÷ê÷*øè÷o÷'÷L÷YøBúîü­ÿŽ~˜{¼3Ó*ARßn8“ & R ¡ ý R ¡ § C Õ 6 ü ˆ ƒ ´ I öF«L>—¯¾Ó¢AÖz ž] @ œ 2 á  ) 7  iTi (ÿÿHÿ#ÿ‰ÿT/  úÓÿÚÿÕÿ¾ÿ½ÿªÿYÿêýœû½ù¯÷¨õªó¹ò4ó<ôgõÅöÃö>õhóòWòÙó¶õÏ÷Øùûfû‹úIùøL÷÷“øÜùÖúWûCûwúJù§øwø\øOø5ø*ø=ø1ø­÷÷)ö@õ²ôõrö×ø@ûêü­ýÀý•ýÔý%þÍþÉþ¢þšþÿp*»‡2×w"B4 É 1 ö 5 X Ý t h h × › ¯ à M € À Þ ÿ È Œ H 7 5 • † ¸ ˜ªÄ , @ ”g0U{3xÏÿDÿþìþ¸ÿYˆ¹õÿ>ÿ#þ¨ýÙýlþYÿ½IÒÊÿÖý\üdúMøöõõ«õ–öü÷ó÷ŠöÃô=óóòóiõÖöé÷ÖøuùªùpùöøÖøzù‡ú€ûîûÓûOû6úùøø¢÷L÷íöŸö€ö×öb÷±÷Ì÷Ì÷¬÷f÷Í÷øøïú5ýæþÆÿøÿJt¤‡Ôÿ8ÿÿûÿ¢öˆüWå˜4§]ýp´ÿØ º  M亵Ö'e²û . w Î ] m ò ´úFÈ•å r % ©t8ÂŽ`²^²¨“’›Ñ¥ÿéý‰ý†ý³ý¿ýÁýOýMülú!ùÜ÷öwô#ô÷ôöƒ÷Âø‡ùøÙöLõsõuöò÷‹ùÎú¸ûVüûûû¼ùÝøBùNú«û‚ü¾ü…ü˜û@ú!ùqøøè÷á÷1ø£øûøàø4ø(÷öçôrôiõj÷¹ùŒû®üýSýºý{þ%ÿÿ€ÿLÿÿ$"†¨•) L ¦ X ¡ Ù&Ñâ3œÖ&ô‹Õq’j l Ö A¸ ¤ X   Ý1¨4Ö[B š©Ð Œ’ ÿÍþóþ1ÿnÿàÿ]ÿ–ýükúŒø‰ö#õõ…õ_öH÷]÷9öTô×ò¬òuóàôqöÁ÷üøçù3úú˜ùkù-úûÜüÌý þíýýÀû•úúËù¡ùVù”ù.úßúþúíú`ú–ùÐøtø ù‡ú!ü3ý^ýAý ýDýÎýBþpþnþJþŒþàÿã¹ØM½Úè÷˜U} 1 žàÊïý,D^fU pÕ™Þ«# ù i  ¸ ¬ b L VêåÆ`µ>5¸Ñú‹‘âwµŒÿ]ÿvÿÉÿL̓¤ÿþŒüéúåø÷úõ ö6öâö“÷‹÷föªô;óXóôVõÙöZøÁùýú ûºûû“ú¶úEûü‘ü½üÕüuü´û ûºúKúÞùwùSùšù ú_útú@úÌù&ù×øbù¸ú‹üúý¦þþþ ÿ1ÿVÿ4ÿÄþþZý?ýEþ-íß‹Õ:Ðù)Å  M ] ©'´ÇkÓ>².ktgN3Ž‘ & u , a 3 ø²èå·ÿ‚ÿŠÿ³ÿM#UþÀÿ¿·ÿßþ*ÿ¥Y¸s'cþ¾üVû¯ùø(÷Z÷FøZù\ú8úùu÷]öJöúö"ø¡ùÂúûÈû_ûºúºùòø*ùú}ûˆüý%ýü¤ûïúzú@úúðùúCúeú4úïù§ù7ù²øÆø®ùAûøüþzþƒþ³þ'ÿËÿNm=ÒÿÑÿwÑúŠŠ€±ezn2ž Ì‹¦Ä61Jz‹š¡¥uÛÊÞ{f ÷ ¡ r t Þ `^+= ÿþ6þ$þ{þ4ÿC‚Ûn”pÿ›þÇþ ÿ9ÿFÿEÿÕþÒý’üû³úŸùXø€÷Ä÷ŸøqùŠú3ûàú‘ùXøô÷lø8ù%ú"û8üBýýýrü´û‘ûÜûhüÙüúüßügü†ûóúËú×úëúûRû”ûÂû­ûû5úDù!ø²÷ø.úü•ýQþ‡þ§þÿþsÿÜÿ(ÜÿAÿÛþBÿw¾€ ÁÝ5‘ ¾ß> Ã Õ  ÂV2} àhØWÓóÏŒkiåïCn ë ¶  ÿ:þb»ýÿ¶ÿeÿ1ÿŸÿ§\ÈÆ,<’þý™üåühýýýjþÿÏþþ´ü·ûoú7ùì÷Å÷Oøùôù˜úgúMù ø~÷øRùcú\ûü¤üÁüaü§ûû+û÷û$ý'þ½þÔþœþÁýâüTüüúû·ûrûûªû½û˜û/û—ú´ùËø£øWù{úbû´û»û²û7üýþçþÿ²ÿóÿí8$w¿%ª7¿íÉÎrŠ^ — â×ÀÊ  >:!î’ÊÔÏá1ÜçÌ ; 5 ² Õ•7®µw´þØý¦ý®ý%þÿ#$!]íZÿÌýðüqüPüÈü¹ý%þþýâû¼ú^ùõ÷ñöö÷Ì÷ÃøGùúøò÷½ö&ö¤öá÷‹ù\ûøüIþÿÿÐþEþ-þ°þ­ÿ”úÔ6ÿþPýÕü…ü=ü4üOüeüuüGüÙû,ûFú8ùÉø€ùû²üÍýOþmþ”þÊþåþ¶þ@þ£ý<ý—ýÌþtöö‘˜CÓýË¬â”æPr±eóg²F€xë;`àvŒ ôP´¤1¡S®ƒK7¤Ã.meŽ'ÿyþÍþbÿßXÇþÅüûùO÷çõ|õöÿö3ø(ù"ùî÷„ö½õéõÎöKøåù(û)ü•üFüûÏúßúÎûgý2ÿ“)ZmÿÆþ’þ‡þ\þnþ©þ…þ6þ¹ýäü ü ûúú ûéü¥þ´ÿ8*·ÿvÿ-ÿÿ×þhþÒýEþ1ÿy’1¨(»Œ|9¹÷¶Ôà n # # ÊÀœpuÄBØÎå+Ïë* ã à ôŒêƒöÿ¬þþ‘ý¤ýàý%þçþòÿ׊ÓÎzÿlþòýÿý<þÐþ´ÿ íþÍý1ü¥úFù¢ø˜øÅøù_ùhù’ø‹÷÷°÷®ø°ùúû€ûûûøûÁûfûûJûðû¹üVýký4ýåü˜ü¹ü$ýÝýþ ÿ*ÿ´þwþ þŠýEýý³ücü\üÿüþ9ÿLù <EoÑÿÀÿ¶ BÐ좫¨¯ÆÜqawB]˜Ùò5Ï]c>?EOOov†1 " v  z ªÕ¯&r”×ÿ±þþþþZþ ÿÈÿFŸ.‡ÿÞþGþPþ‹þ½þÿúþQþ'ý.û'ù“÷cö ö‹ö6÷ê÷hønø<øø$ø®ø~ùÃù¼ù±ù£ùßù6úæú‡ûü©ü-ýdýŽýeýýÙüwü'üü/ü‰üóüAýxý™ýŒý‚ýxývý˜ý«ý¾ýþ¼þÁÿà½F€a VŠúÿØìrµ¹£trŠ Krê…•–ç«ã»Uèƒ?0(:ŸViVßÃ`ÉÔ®Rà͈ŠïJæ'LXÛLÿÿ>ÿVÿüþØý|üÕúÝø÷öÜõ¦õ„õnõ?õõûôyõ÷Äø$ú4û‹ûlûÐúåùzùùóù±úQûüŒüµüðüØü¹üÅüàüýýäüÚüéüý–ýþFþ@þøý~ý:ý$ýDý›ýFþÿìÿµ*±äÿÿ¢þòþÛÿ)FU<‹n@䣻wø¸ ª ƒ ƒAN¾ ±âËœ§Õ.¸`K¨=¹ðЬ€CŸ³*ô ûI‚Y!°K ñ±öªöÿþØûýùÆøø÷W÷÷ö¾ôô®ôö øèùbû üäûûãùÐøQø’ø‰ù¥úÉûÊüZýOýÛüPüêû•ûŽûÖû2ülü‚ü´üýƒýþ”þÿ³ÿaø\ÀXGüDÅþtý„üTü±üý|ýÓýŒþPÿ4».¢íÓ[  - ê d ¥ [ B Ü   µfv0ËÝQHõ£†ÿpþMý[üüÁü”ýxþÝþcÿ.ƒ[&%§î‡YÄþÿ„ý²ûú±ùYùuùXù ùUøÁ÷s÷ øFù®úãû–üÃüü”ûxú{ùù÷øùVùµùLúÉúû÷úüúDû†û¾ûüHüküüôüYýÎýPþæþŒÿL;2D,Ó&ñ²YÿáþËþ‹þþpýþü¹üëüzý=þÍþhÿW¼n'ຕ Y  n - B  !næu»Ê%³Îý߯Etÿ ýqüüüaüšüaý¸þùÿ¸îOÀ>ŸÈV‹^ÒþýÒúúø¹÷÷ªö}ö+öœõõYõöTø‹úkümý¿ýBýbüû(úÙùCúûÔûüåû”ûûoúÌù;ùùWùêùŠúûŠûü[ü¯üýbýþåþ568YŸ=’! ªq¬§ôÀËÿÿWþþþcþÿÃÿ{ ø=¯õ³­gV¯itŒ Z – '  †×f^kÀyQŠ}˜5+OþPýüAü7übü[ýÈþíÿøM›]I×d:ís ¨ü½ù÷éõ³ô/ô£óþòaòfò³óÞõDø¢úrüpýoý‚üùú_ùyøYø¥øOù úûÐûütû”úÅùHùù}ù-úû#üûü}ý£ý¤ýÏýþ’þNÿ6þÕÛYiÄ«ò;½Ãzÿ”þþ!þ«þ²ÿìÏýE®†Ë¦ô• D ` Õ x ª Œ M ­Q¯óKíÀï˜Sâ1;ÿkþÍýþŠþdþ‰þÿFÿãÿàÿàÿ5ˆÅ,pmM>ÜÿþÈûúø[÷jösõMôMóóžóõ ÷Ñøtúqû"üéûÔúù¨÷÷"÷|÷ò÷‘øsù!úÈú ûYûrûyû~ûzûUûlûÄû ü>üoüüýÁýÅþ×ÿʈ‰³'QïÖfŸÍ舋·Lÿaþ½ýŒýðý„þøÿ<ÓP±ÙcÖ¥ÔgV  r 9 ‘ …_B%*·òú= 1©¸×»˜aÿ‘ýWüêû´û6üý þ &Э*¨Îu—‚Z²k5þZü»ú)ù¿÷Ìö•õ&ô óÓò£óLõîöø÷ù"ûÀû„ûEú¹øb÷§öªöÍö*÷½÷MøüøOùùœù}ùfù†ùÄù.úÍú¢ûüNý$þÑþXÿÕÿg¶®¡  ¨17‘/‰¹tRç cª7 3vмð¾éj, þ ¼ K .   ˆ|¸áÎ…¾ÛÎãѤ¤Ž6HkþòüøûŒû}ûÖû¯ü¥ýƒþ ÿDÿlÿ¸ÿ:!83Û¨¨þúûú`øîöÏõŒôvó+óÛóŽõÅ÷ðùËû ýºý»ý«üËúÕøE÷€ölö—öÂöÂöèöøö(÷€÷Þ÷Xø ùÌù7ú›ú û•ûüeüùü¼ý™þˆÿ©€êo&H«µªÔ üo0íßÿÿÎþÿÁÿËPdû—   d ( ¢   m ò | @ j  œ~ß{Åö¼ãŒFfßÿÅþþ`ý¯üIü²üýPþ|þ¸þÿ=ÿsÿ¼ÿrT=½F?þcüú_ø!öœóñûîÉíIîqðêòfõ¯÷–ùhûtüoü›û?úù?øò÷ä÷»÷å÷røÆøùù—øFø#øsøÜø˜ùÁú-üfý›þÁÿ¢Uën¿Û]@‘Û‘] ‚šW„se·BÜþÛýNý7ý¶ý¥þe† ß >Ì÷=ÙšaŒ($¶ • * ¶H°[^ã `{þýü‚û~û¡ûüdü&ýGýRýEý0ýŸýLþÿ áZ|EÙÀþÑü]ûúXøö!ô¥ñ\ï›î ï òôô¸÷íùcûíû…ûú÷÷öáôyô»ôðô!õ$õ@õ–õ ö|öÜö1÷øÃøzù9ú5ûSüaýþìÿOFBåïêYcÕé 7 ® ƒlÆ9Akc³ÿBþüü%üéûXüýÂþBš¶î  ä þ u'ðwI!ý,æ I k6ÝqS֊İŒí ¨ÿdþPý—ü'ü‰üýËýÚþ‹ÿüÿÿÿEÿßþ¦þ¦þ}þþòþÿ¢þ{ýêûÒùå÷ö¯ô óñðÊï¾ð×òQõ€÷.ùsúQû‰û ú¾ø´öõ@ôô%ô5ôô*ô•ô6õÞõtö¢öèö,÷G÷¦÷;øùÄù·úûû ý[ÿF6Å–ž Ü!¤þ³â lhl‚ÿûýåüiü›üòý6iïé Ø ö Å ƒkš©HG¨“'t ê X  -ug¤Í°bÔDè;™þuý†ü[üÙü%ýäýqþÿ}ÿ•ÿgÿ*ÿ£ÿ$Þjìù(Þÿ%þ5ü ú8ø“öŸô òøïï`ïôðóeöúø8ûŸü0ýzü¾úÇøóöÅõõyôôUóÈò©òþòÀó|ôõÔõdöÊö+÷°÷FøüøíùbûýÖþÄìἚ2.ñ²ñÚRüèÿ>þ@ýËüý`þ¾ë^A  ÿ ¨ ? E„žæKô* A D x  % ¨ J ˆ * + ÊIpªÿžþñýþ<þwþ+ÿhÿÿÿþžþˆþ“þÿãÿöÿ"çÿ<ÿ þgü¨úù;÷õ§ópñ-ï‡í‰í%ïÑñÒô÷úêû¨üWüùú+ùs÷löåõ}õõ‘ôåóTóøòíòíò%ó|óçóEôüô!ö ÷/ùõúÃü™þ-gký;v~À¸îbƒ¡|"×äõ\­ÿ&þMýðüæüÓýÌÿº6x é ^ ,óÍÆâÍ*ÃØƒ– , È a CÙêLJK©!*žSÎþ¢þùþ/ÿŒÿ&K¬¡¹ÿÙÿðÿ’ÜyÓ NZþVü,úsøuö7ôÄñ¥ïËî¼ï¼ñô öAø-úEû‚ûÓúÈù‡ø?÷:öUõSôOó.òCñÝðñzñÿñeòó©óYô]õ|ö‘÷ÇøJúòûZý½þ)W$ é@´ØO·Q$DñÀ1ÿý5ûú´ùùTúKücÿJ& M œ ÆÍfm°C\)Û›” q + g I ˆ Ì · I Á A qö`êГäpù("¯=Ï:‘ú& û ¼ÿ0þJü3ú(øvö~ô&òêïî»íkïtòëõGùüpþ‰ÿUÿþüûùøÞö@ö²õþô2ôOóòòØòó[óƒóèó ô=ô»ôfõö ÷vø"úÁûrý<ÿŸ´•‚ºüÿ\õ'•ߎ±×£þ[üÓúúôùŸúpü™ÿ’2ô Z  ~  o”rÕhfõ _ Çqž±”ƒã§"+¿Õÿ×ÿÇðøÏ£í!×”[êi+ˆSïÿSþKüúÖ÷zõíò[ðÛîéî„ðEóŒö1ù,ûü<ý,ýüyúåøÆ÷C÷ÃöaöÐõ õOô ôTô¾ôVõöœöáö@÷»÷^ø ùóùû„üÚý=ÿµÒ1|ø¿Ðµ'³Ÿ‚R¾C$A¢zÿýÉúùÔ÷`÷øú8ýÒ_ü¡å E å Êl£?-{"^Ÿ " å ÖQ? ¬ º Z ©óó ‘SÿËþ¿þIÿÚÿgÀÿd¼¦ £{ Kš%jLmþ"üúö÷{õÐòûðcðfñóöBø>ú¿ûŸünü?û–ùø÷öWöö—õÏôèó:óôòßòÔòõòLó¬óGôþô1ö™÷Aù;ûsýTÿ gw‹øæ‹B[±/žŸ¿<wQþ?üäú8úú·ú‹üeÿͲâ ÿ ã ×  Im-˜q! Ï ¸ ” —è]Ëõܘ(—ÿRþŽýýÚýaþÊþ.ÿòÿ92íÿ9!šýx—Åiàÿ%þþû úÓ÷ õ£òÿð"ñÙòNõøxú{üÑý9þ þ(ý°û ú°øø«÷÷'ö!õô¢ó€óóÆó3ô¨ôßôOõçõÒöÓ÷ùƒúçû=ý‹þèÿóµY…€†Â4-E‡óŒ1GÒÿ2ýû ù©øDøÚøÁúðýc­W ™  s40[+Î B ¦ Õ+*Ê—Ãï#<ž<Þ5éË’0¾K6Æÿxÿ€ÿçÿs ªÔÿÕþ þŸüû•ùn÷¾ô4òwðmð°ñ ô¬öùpû"ý0þ8þ<ý¯û/úIùÍøøE÷öÇô©óÑò¢òÚòóÍóOôäô±õ±ö¼÷­øµùûpüÐýVÿ·¡iN”'Õá {_’¨êÀ±`þÞûøùløu÷A÷søûúþB!í õ ¾ ;¦êµ**ƒü~ °mç?œRà;cŸxp§žÒþþþxþÁÿ‰‘kª©XÎÔj0ôð/ÿVþ‡ýüCú ørõŒòaðÏïcñ-ôj÷]úÙü¶þ•ÿoÿ?þ{üÐú–ùÂø7øV÷#ö¤ôó,òçñòòPòñòzóô¬ôƒõ¦öú÷ÇùÅû¿ýÓÿº Ñ=ÆÅóé S#ÎsÿÌpß¶$ÿ×üû½ùÏø¢øúù–üåÿ!(_¥ @ 2 -ÍïkíÃD ß } = %”t%l›è;Lê•ÿÁþÏþKÿ´¯: Ôñõóµ¬Ù‚dh}qfÿ!þý;û‚ùÌ÷ öœó€ñ;ðŒðJòñôÒ÷Èú;ý6ÿV.ÿ&ý@û´ù©øÖ÷ÖösõîóÃòøñÁñ°ñ¥ñòiòÔòaóôÜô¡õŠöã÷LùîúùüÈþ.XúÙ ú; ™‹Ñ [s Å[Eÿ²ý5üûŒúû'ýøÿ¢Mˆ¯ -  ÝaV±FF›„ £  µÁfhEápÈ^¥zFÆþ7þþÊþÇÿ¡íEÑ25¦0[,d³t– 62ÿoý­ûUùuö@ó«ðïðúñ¸ô±÷˜úÕümþJÿâþâý®ü²ûüúWú—ù˜øD÷öIõðôñô¬ô½ôÓôÞô+õ~õñõ`öK÷ŸøRú üÈýsÿ’%O÷Q22x@Rn?în *ÉýÎû6úÑøøKø0ú^ý7Ö‡2 Ü Ù ÉqlÚ±X¡â r ì •¾]8Ö] èzWÍ7Qÿçý~ýõýôþµÿÒÿ!<'Èÿ‘ÿüÿ.¨’eƒ4 þ•ü³ú¸ø-ö{ó™ñéðÁñÌó[öþøXû4ýcþ þ/þWýkü×ûxû>ûÐúÛùSø¬ö9õ"ô^óÑòÌò!ó»óô†õ’öx÷xøúÚûËýÿÿ(¾Ô\ܲ´Œ¯ºP²? T·‘þðûxú2ùGøJøù ü ÿà]I = Y #€I >AŸß W   ý§ÜC–Ü[ÇøÃ]ÿ5þTý¶ü'ýþÿ<‡8áÞwÚ7°ÿ^ÿBÿ–ÿÕÿUÿÅþ þ!ý û úløö§ó§ñ ñÈñÆókönùü9þÅÿ•ALÿ.þ5ýŒü*ü½ûÚúgùå÷Göùô!ô¦óÏókô1õö÷ øÍø›ùÕúZü!þøÿÆñˆ½ât†è¼ÑëRɾlÿ‚üKú‡ø2÷Æöú÷súüýœªÞŒH  >3±˜×q¬ ¨ à Na4m³˜¨E°þý+ü)üëüÊýŸþ(ÿºÿiªr%çÿ¤ÿ>ÿ'ÿTÿxÿÿLþ7ý ü‡ú ù¯÷½õGóCñð/ðæñwô@÷ßùýûœý~þ¤þ?þ¢ý&ý÷üÐü²üüÊúùG÷sõôó_ò@òUòùòðóKõ™öÆ÷(ùöúÊüÿ€‚ÚÁxn³ Ê ~ : ¥}J:GÎ`OÕÿ<ýYûÖù—ø#øåøëúþG ä CìäI4eMÆ n  ) ƼeµÕ.=ü{µÿNþ&ýzü»üaýÄýÐýþ;þjþ—þ{þ´þÃþ¸þëþNÿyÿ;ÿøþÐýÊüyûÍùøGöÈó[ñïï!ðXòõô“÷úùêû6ý©ý,ýOü¿û±ûëû%üünûCúÕøq÷‡öÔõQõõõõõÿõ¤ö2÷ø‡ùtû¡ý!qHo.$BÍ ² · Ì S'=Æ8ç=ýõú^ùSøð÷ø…ú’ýÏwNhh§A ó „ ¤J–hÅò  C m £  É Z …¡ûX„ìH„ÿqþ†ý¡ýšþKÿÊÿ#A_ÿžþ7þÎýtýýøý8þâýý(üûµù†øóö õ¹òñpðñºòóôX÷‰ùNû‰ü ýùüüHû¯úqúSúú"ùù÷³ö©õÀôôšóKó ó'ó¿óÜô;ö±÷+ùÜúvüXþr;m"¨r­7° | Z ~ ê ± +   -b\Òþüžúþø¥øçù¥üÏÿX1ª=  × 4Þ<V÷§ ü R ´s¹ † UwoøÅÿ^þ¥ýžý˜þÊÿÉèÌ‘UêÿEÿÝþhþ¹ýHý[ýÜýÊýýüûù¬÷úõFôqòxð%ï¿îÛï:ò'õKø'ûýEÿóÿPÿõýˆü¡ûûÆúKúùyøJ÷PöõÐô5ôËóió0ójó>ôƒõ÷“ønúoüšþØÐº,­º3¥ O   A?4ù#ÅÿVýOû§ù—øºø\úOýL©%  ~ ú D:Ï-%~!›  – ^¸Š†,—±W¹IÏþ?þ8þ(þ¼þ¹þ³þÿ4ÿßþ½þ¢þÿ ÿÙþÿ~ÿqÿ¤þ7ýªûÎùU÷-õ?ó-ñÅîúìiìNí_ï?òƒõíøÊûíýûþÈþ•ý3ü7ûÌúÙúëú‡ú}ùø­öqõFôRóÝò›ò×ò[ó8ô~õÄöý÷QùµúMüSþCÐל¹je_ Å  i î ì ‡ ·[yTç½þ/ýÜû¤úcúxû¿ý×âcø - Ž V äëQf4kP ª  ¬±\Dü¤AÞ'*`æÿþEü¯ûäûÂüþ—þDÿ3·ëé–%ÿþ›ýžýýžýkýÐüÅûËù·÷?õ‘òÞïÖí:íDîdð2ó7öýøZûàü•ý|ý»üü’û‚û±û¬û û¹ùø„öŠõ¸ô.ôâó°óÌóBôôôöòöñ÷ù}ú[üØþ MÍåó= 2 Ím®O Ò á ÿóhéþºü¹úù—ø¨ùYü¦ÿ¥æ„% â œ 2=¸ôÝ&ü… " ‘ A hÒ$`šó‹õ«9®ÿ@þÆýŠþÿUÿ¨ÿ»ÿ5¼Zˆÿ‚þyýÅülüjü¬ü3ýxýóüHû ùRö˜ó(ñnïíî¦ï.ñ=ó„õï÷ ú¨ûÆü ý·üÊû°úãùUù ù¼øQøú÷ç÷Â÷÷÷öæõ-õÐôèô„õ¤öÎ÷¯ø¡ùøúpüþ¾·h+ÎIš 8 b Ô ‘‚Ê yþAüËúiú-ûýü÷þõõùÕ¹Õ + ${5‰“)Ûa  ö 1 | i -i¸‚Ãüi<*ÃÿQL„/ãƒUhþUüúdù:ùåùéú#üVüûáø¥ö½ôLóòñWðð–ðŽñõò¯ô³ö²øOúiûÿû2üü¬û~û¤û¹û‰ûäúñùløö•ôÏò©ñnñêñóýôX÷ÒùüFþ&ù»3VÞVÝÐjkH h ž ¸ X œ@Ï¿±þ—üÄûÆûýûü.ý,þ¾ÿë¦ù Ð ` ¤žP±–¼‚* ¥ õ µ§,ÞÛËcõ–7gÊÓfò·#kRýSúÊ÷Pöäõaöì÷®ùÑú1ûùúúSúúkùLø÷éõõVôïóóó ôÿõÐ÷Åù<û"ü|ü¥üPýkþ<ÿ©ÿÇÿVÿ¨þïý*ýùû:ú?ø‹öõ)ô1ô½ôêõ`÷êøÀúiüÀýùþåÿX‹÷-½'RNŒsFÊŠ¬äɼ …Öf–7 FsµœÛ ° ˆ G ¶ ú S ¯ ƒ ô 4 E û ³&‚ùÃAb‰"‰ÙÇM Õ>={ÿ&üEù5÷1ööqöÞö½ö†ö†öîöZø˜ùGúhúîùùùÈø¡ø²ø ùù$úsúnú8úÁù™ù8úsû¬üÖý#ÿ.gD¿Üÿ€þ,ýšûgú?ùlø_øãøŸù¢úóû4ýÐý¿ýšýÈý›þõÿ‚úWnïN¤Àµÿ@ÿ·ÿËØLq½ ó ËYÑ ôzÐ&É»Ä =R$ñÍÇ.{…£#À-fp ɉÚÿþ~ü!ûTúÇù­ù¥ù¯ùvù3ùâø$ùùÖùOúÃú1ûkûZû„ûÞûŒü^ýðý þ²ýÑü¨û­ú‡ú&ûüÈüqýRþ ÿÿûÿ÷ÿ˜ÿêþMþþþýåý®ý`ý5ýýóüþü2ýýßý-þþ>ÿ C¿÷XV¹Üÿþ0ü'únøœ÷øVùûÜü þ&7åº8 Z  ó : / ; ’.ÓºáÚdvxïµ>µ4ß* Æ ‹ v r “ ^ äÚþ×ûÅù‹ø2øü÷`÷Cö¥õõ§õ÷õö;ö˜öìöT÷Œ÷Â÷%øÑøñùLûÈüCþðþŒþýûnúãùïùAúˆú•úú€újúvú¥úâú)û}ûüý'þ ÿ¥ÿXy†ß)Je°%`Q¢,Q¶ÞÿdýåûûÒû,ü{üâüóýxÿ4 þ§  h o $ÏþïmËâøÑ2b‰Î º¾kæ†ì‚ ð  F o *03¶þýwû}úùMøöôçòÛñéñtò`ó’ô öª÷÷ø¡ùèùú{úû¸ûiüÝü ýêü«ü´ü–ü1üÉûtûõú¡úTúúüùúùùüù&ú„úëúïúôúRûãûÀüþÿlÒ‚Ò‰d²ï–›ñØ…þý ûrø÷žöãöX÷Ú÷¨øòùÎû_þMZU¼ Z  Î ö ö ôÉŽs›Ù,ÅÄŸGÜ…ÃŽ½û ã ¼ ¶ $ ‡ —é’•¡ÿ¢þùýRý®ü üCû úØù"ùHøÉ÷†÷ž÷OøQùîúÍü¼þ#¥Mÿþâýäýpþ%ÿzÿ’ÿ‰ÿåþ«ý·û„ù„÷!ö¸õòõÙöß÷ºø+ù’ù¾ùÝùúúTúóúÓû4ý ÿRÓ$™ÛÓÑ8wÿÉüú ÷ÇõõjõJöp÷Žø²ùûÎü¶þõ‹iï « ” è  Z_B·_’•)iY™ë˜Ål=¯ Ú G Q 1 ’ è@¼svþ½üÈû>û„ú½ùUùHùˆù ú˜ú ú4ú©ùùsøó÷æ÷DøPù¶úGüþÐÿÔ'#+A¸=«ÿÿ–þÂýÓüÄû÷úxú\úÂú5ûûíû8üÕüjýþ˜þ(ÿÍÿŒ´˜ r|  q ª  ï ÓÆC0ÿ½ü#ûÈù»ø-ø#øåø{úxü¶þ 2¡Ê'D>õ˜W†»ÿÛþjþ@þþþ6þëþÅÿ5ùzÓpüLø´ÿrýQüû6û‚ûËû"ûùõ÷¶öÏõ¹õÊõ ö1ö™ö5÷æ÷eø#ùhú üý¦þfÿ¨ÿ£ÿ}ÿÔ‡p™<‚îrâÿ%}ÁBòM‰ÿßþ2þ|ý÷ü¶ü»ü8ý1þ§œ`D 1  þ /å¿ÿêûäùùßøÛøùkùBú˜û‚ýðÿŒª?Š“  ÑE:Û?ÑÞM7hÊ™BP9+lšIØs  ? Ò À˜ 4‹ý·ûÜú~ú³úèúÌú/ú¿ùùÂù5úÉúÝúeúƒù¤øÅ÷ñö‰ö’ö<÷ù÷¶øù)ú_ú¼ú•ûäü1þaÿ)k7¼ÿ_ÿòþRþ¾ýtýJýGýuýíýYþêþÿ¤Ž8ÿQþ ýÅý'ÿp4ãÓ ] ß é\IÍXþný´üôûûnúúPûÿüDÿÛWD … í Ä F ] Œë/¯ª%YÿÿäþÞþþòþvÿ ñIY  º @ k £^ÿmüúùÆ÷C÷ËööMõUõöÿöø©ø¹ø\øÁ÷-÷­ö±öK÷“øú£ûÓüÄý;þYþœþTÿ¥ò$䆨ÿ~ÿ÷þ¬þ®þÈþ%ÿ³ÿjNFJ”ØÅzN1ø@÷   ¢  ì , åìYkýwûcúÉùNùÿøù×ù*û÷üÿXj 8ë6,éT<ïBëWÿÿÃþþÆýhýúü(ý{ý”þµ D"yØKÜxÁ]ü¸ø*ö‰ôqózóèó<ôôJôõRö¿÷ù†ù¤ù¢ù ùLùÜøÁøIù]úûÕüøý×þeÿîÿÂŤ&¿ú)„wÿñþ™þ~þ{þäþ‹ÿD߆ú߬R<…ËóÕÞ k+Õ³ ¢ö}´ýùû£ú]ù%øƒ÷Ñ÷Bùû•þìq.  4 ® À –"ŸŽA¡÷ÿ«ÿ†ÿ~ÿkÿHÿ<ÿHÿéÿ?#$u* < …‚¥ÿ%üùÄöõôžó óYòûñòò…ó§ôXõEõ ôòó/óÊòþò ôÈõÍ÷ÈùLûDü©üÊü$ýõýÿáROç»Pïÿ¿ÿ™ÿ{ÿ^ÿ*ÿÿAÿ”ÿàÿ)L…§ûïÃSq ] Þb+C „ ”«ÿÅý¤ü¤ûÈúPúvúwûSýÎÿ§³B  { d Y ó  ð‰ûçôÌ’’ÿÒþÍýéü³ü·ýRÿlv“íŠÞUÿü}ùy÷ÅõÍô3ôéó­òÛñññ­ò óôBõ}õqõvõ‚õõÑõQö<÷køƒù‚ú^ûÛûQüýJþtÿ>¾âžK(aªìgë#óþçœ(úÿ[ÿÿÿäÿÈ®‰ ŽÃ)Ö à g Q=ÿ)ý«ûQú!ù…ø{ø6ùñúnýM+³qa¨²pùó’WWu®s“IÁÿJÿáþ[ÿ‰AI‘3= b ŽóQÑ7ýÕùN÷Oõô†ó‘óóÂòOóFôiõFöÍö®ööRõÐôRôô$ô õ6ö|÷´øÏù‰úû³û¶ü¸ýþ2ÿ§ÿÝÿ|ÿ$/ ë· Ó&®]Û5!¿zI«Åj+ \ Î`Y®û œ " äÿÖý¸üüpûûû¢û5ýÿA:å ´ y ® l ¸  ?&1˜<ÿ{þþùýäýhýZý_þU°D#  y ˆ …, ü³øöô²òò>ñ)ðpïmïð-ñtòXó`óIó7ó[ó™óô¾ô´õ­öœ÷wø$ù£ùúçúúûý¶ýýýßýjýñüâü,ýný¯ý?þúþÌÿ¯\Ñ*€ÏãÍyÊŸôa[’ “HCœU øDøÈÿŒþ¹ýÃüûû£ûübýpÿ(ï+ Ñ «  0 ì  ß ) N“Vc‡ÛÈGKuÿ ÿçÿ˲*Fá - à +QýOúÀ÷Æõµô{ôÃóƒò`ññùðEñ¡ñüñ òÕñ§ñ‚ñoñ’ñ4òGó•ô!öÃ÷7ù/úêúÃûÑü­ý7þ\þþoý¯üü§ühü_ü³üFýïý þUÿæÿUÐB`f/ÓÕ\nÌ ˆ $Oß Z ´– ±ý%üáúÙùHùEùúlû¶ý›Õ×  é q X¾€i • J % ƒ›\´Wÿ9ÿÀÿû”AŒ  ä Ÿ £ #nxáüú5ø˜öŠõÓô¶óeòªñ°ñ‡òäóåôlõƒõ)õ–ôêóVóPóô\õÓöŒøöù­úû1ûÜûýþ þ’þ+þ¤ýxý¢ýêý¼ýÐýüýPþrþgþ/þþDþáþ‚ÿ&hNÿ^þ¼ý þ©ÿ‹( ÷î+³ . Š»eþÈüNûÔùù&ùýù¦ûþdY¼ f 9 ˆ Œ " R {ïýJ¥Qn/"}ÿúÿæz,üW  b v $ªÝ~ýÊú{ø®öOõ8ôÞòoñ²ðð9ñžòäó´ôDõsõ£õjõ÷ôúô‹õSöüöÂ÷KøZø<øiøJù³úü4ýâýþ)þvþîþóþŸþ¦þÐþ@ÿ~ÿ©ÿªÿ©ÿœ/´¯ÙàÿHÿˆÿÐ*€ E —Ýp í bßåÄþýrûú'ùùúËûOþlçæ" P r X  ± ê ÔH¼ÇÖÇË!ÍU“7ç{® = T ¼ l = è_Êeþ¢ûæøËö?õÿó_òªðiï)ïÎï’ð„ñHò¶ò ó7óñòêòXóLô õýödø²ùnúÙúwû?ü!ýxýˆý(ý„üõûÒûýûéûÒû*üýþçþXÿ–ÿÊÿDÙ ?„nÿ•þ@þöþ¬UkL €  « º ^ U 3 Ï€ÂÿXþýñûˆûÊû·ü>þlmƳ ã @ ¬ Ï Õ A ú 9 ]s<@Ûÿtÿðþ%ÿòÿg{7_ P £ = ! Ñ F u€÷ý#û×ø¿övõ†ôióÚñ ñÿðÒñÝòíó“ô÷ôÇôrô¥óóÂò=óbô–õ¹ö¾÷4øø/ùVú«ûŠü ý9ýýûüÊü½üVü­ûhûwûü’ü$ýàýªþžÿ¸ lƒ©ÿ"ÿlÿÈV ù “„k°â ã æ,ÿ4ý¨ûŠúÌùœùOú“ûµý{¤ô½ Ò ï n ¬ ò  ® Ê äjA>l|¦ÿkÿµÿ¿íš? w N „ n  -J¿ýÃúPø¼ö¶õ×ô†ó´ñ‹ðvðñÿñ óÎó:ôeôœôbôJôcô]õ´öÿ÷ù!úÔú+û”ûküDý¹ýËýyý ýªü¤üôüýùüýüˆýþ™þ¼þÆþµþ±þ²þØþ¾þÝþ×þ¶þ™þÜþßÿÚ1; K t± í * MràfþÜüÁûÜúú¬ùúüúýÛÿ"² à æ U i ^ ê ö < Ž1..XZsš>ˆ5ŽÔv_  … ê t - Õ ì&?™ý’ú{øãööZõüójòXñ>ñÿñ&óÀóôjô‡ôqô8ôýó>ôÑôaõ:ö^÷€ø6ùÒùšúÙûýçýWþHþòý›ýŽýƒýkýý=ý¢ý=þÿþôÿ¸síþã‹Í×ÿ¶þÊýýtþmuï% ³ 2ζM B +N7þ?üÁúœù±øøëø@úEü&ÿqÆkh ú J f í ý ‹ ,U¯Õž”"]Ðÿ(C7Ra R ÈBµ „ ^cýlúø@ö<õ`ôó}ñÍð+ñŒòÙóäô”õÖõ¹õ<õçôôîô›õMö)÷øóøƒùêùXú ûÌûüLüQüüÝü‰ý$þþ„þ†þ´þÙþöþ ÿ9ÿ†ÿþÿ˜’µRÕTpŽËÇ4 Í WÕ9 F 﫾çþ#ý€ü1ü ûóúëú'û÷û’ýÕÿ˜tѨ ¢ û ( I Ñ ­ î$2hJŒ­‡$¿8aaû€ Ø p»l@ F ƒ›Èÿïü‡úêøî÷Z÷.öQôéòIòWòòò®óŒôÝôáôìô­ôRô ôAôõ·õŒö“÷¢ø”ùÎú1üpýþØþiþÂýý¥ü…üµüÍü˜ü ýÔý®þ‚ÿH¶ü 'òh‡ÌÿXÿ1ÿ±f õ ÷ Ç» l 2 ªÊ§ÿYýÏûzúWùÎøÏø´ù¿ûªþ;$ ú D   Ì ' è U çØëûÎB€íÿ3þeþ ¥Ìmo € è - Ð CæXÙý²úç÷Yö>õNô^ó‡òòIò óô õÇõiö÷÷Âö¤öÄö(÷§÷|øùŒúOûüôüÜý\þsþþfýÏü³üæü[ý¶ýÐý+þÙþjÿØÿ_:'óÍNÍÿrÿSÿ‹ÿ‰››¢ Ù ý j]Ó ] ¦ 6ÑÜý7üôúßù%ùù˜ùûfýJ#ÃÐH z ‚ © d ù¾äƒå‚ÿäþ:þoýÀüåü—ý1ÿ€Àåx 7 ø ^ ˆ á×Ñiwþ_û‰øýõßóžòVòtò€òò*óóó?ôô<ô¡ôuõGöL÷Oø/ùÖùsú¨úûˆû2üöü÷ýõþÎÿ½ÿ¾ÿ¹ÿÝÿ’iÞkŒÅ´þiãÿ•þ$ÿ½þÕ’ ® O Ì … Ö *K,Ì*ÿÃü3û[úþù÷ùmúqûTýòÿã½Å à þ L m Ë.n‡™®ÿ€ÿgÿEÿšñnÞú \YKîuÿÞü ú÷ƒô–òÈñÅñÌñäñûñ—òzóVô+õ ö ÷þ÷øœø‰øÇø*ùÐù«úÝû_ý¦þÿ!S/ÿÿsÿåþIþèý×ýþoþÿýÿá¦:VQ w“Âÿ(ÿÔþ1ÿww‚4µ ­ l É | ´ Í ÔÉ ý³ÁÿŠþ;þ^þÝþäÿJå-· J ã ‹ Ö ÷6>‘”ͶþRý<üûóûFý†ÿx t½  ì  ÔAï¾ÿ­ýrû0ùÐöcôbò\ñòðáðÕðøðmñ©ñ­ñ|ñ¤ñ5òYókôbõpöÍ÷ûøãùqúûøû¤üIýìýpþ»þÊþíþÿìþõþ+ÿ×ÿl>Üq¨È®Aminî­´ÞóᲿ¢V ¡ Ô Ó “ ­ý¯å–ÿåýõüØü´ý-ÿ3® v @ r G O 0 áY‹º¨sþºüýûñûüØýPÿ7ÖÓïÌÿžþ‹ýXü™ú{øÔöÍõ/õRô-óCòÝñßñ òòKòÛò8ô¿õàö·÷×øúáúnû*ü'ýÏýþaþŽþþhþ’þ‘þ‡þœþûþ\ÿ§ÿ ¥y$ÃDàåÂf ¡cnàoÑl$á¤èè½Ù…dOJö5ÿþ¹ýþÿ>gso$á©ošðjBK?x$Ÿ¯ÿ¢ÿ_áUMÞµÏR*ëþÞý¾üûØø÷"öðõÈõ…õõôTô†óÓòHò9òOò ó0ôõÔõÆöÇ÷¢ø}ù‰ú˜û1ü˜üRý@þMÿ À‡Ûÿ¹€U|Ç@…gÜ kn¾[ÙQÃ-[‡¾|gó…žX)ÞÙæÎ¼¼ë$ŸV>DžBâ³õ–ÂoØÈ7EÞY¤…­û£˜öÜ ›,¯þwý{üÕûÕúƒùMø¶÷—÷z÷¶ö»õ˜ô‰ófòññýð¥ñÏòô4õºöLø­ù•ú^ûRüáü†ýdþ|ÿ™gúYÁöÉž¡ »t-YíÞôwWÏ¡{$©É”§+luV ’™–VÍ|.Æ!rp;) <ßÿ'Hów®qÎÓ˜…DÿðþZÿ¤±hýôÿÝýûˆùÙ÷ãö ö~õ–õÚö—øåùûùLù;ø&÷öõ~ôQôô+õö÷føšù¢úQû×û(üÝû~ûµû•üñý’ÿCö†¢{¾ŒøAœF'ìošÉV’FlªšàѶbÞ÷ÿ=­}Âúÿ“ÿÅÿrµ;rH!Ì-Ž Ï¢åÿ8ÿ·ÿ¼+ ·ÈéJí-ðÿI¯þëû;ùÔöKõ&ôžó—óÓôDö7÷Š÷÷÷ öšôó*óôúõ[ø¢úMüný þJþþãýîýþqþÿ bLêLšŸ™¦m:ÜY¦×©©1‰¡uµÄ}àkÿ‰þlþ4ÿŽoñÿšÿÿÕÿ¿PÊ ©›3…x6Ö>›Ùcx«â« ¿dþ µ–Ñêÿ€ý6ûðøÆöƒôpò#ñýðòOóJôõnõqõ õ‡ôYôkô¸ô…õGöíö±÷wøxù]úû£üTýÙýuþ<ÿØ‘ã G»Ú¸ ®é5saüm;¥CÏÝ   ï s ×Ü”Y¾°÷(Ò &8r]¡J5ùÇwöU§µ5¿š¦öMߤ7Vÿúþ-ÿ.¾=UÑ”Aþ$ü¾ùœ÷xõô³ó]ôõ]õþôAô?óIò;ñgðþïðñ{ò¼óõAöC÷Ã÷bøBùúiúÒú‰ûcülýÇþ ÞëɽÑñZµ–e€ÂíS¼»: H z€èÔD›©û±3èÓíº°ª ·”׳KlÖñ‰m,Yã[€¹cĹj«Hd@µ²ìaÿxüTùQöËó_òŒò8ô}öAø>ùPùÒø¨÷qöTõeôô§ô‹õJöõö½÷:øŠøµø ùùºøDøYøùúhûáühþÿÿ¹Q'$µy'­J —û@/öƒf$¥¥I Q »àÓ¡ú›šÓÿÀÿ]zØ%#ÕÅSÝ~9ÝŠ±Ä=œÁm0vàbn;FñÙ= ‚€/þ¾û…ùO÷¦õ õsõZö'÷÷¡öÙõßôºóÜò òÁñòÖòÑóñô]ö°÷¹ø¡ùhúû;û‚ûü!ý:þ#ÿØÿfû²¹¹:zxUÚ¹AJ¼ÿ4ºÀî Ÿ ‘  õ U î©)ê³Vkjh¶/ûÜwîîuÑߎM}øÀ΋c†ülöê.‹òkkO¢‰ø%Îý]ûÕøö­óLòò#óvô*õTõDõþôšôKô-ô&ôoôÕôDõÆõiö5÷È÷2ø‹øáøÐø½øîøµùû"ýIÿVÀFiàÒjåMÞ˜üðÃÿ8ÿŸÿ­¥æìQ âq¦:N¸îÿìýý#þ•ÿcIÂî´ÄU(ýp¹ñ4ýÌ£Žj’>‰©UPë(­L¼šóÏÿ)ýúÛö•ôüónôtõgöµöšö+öIõHôˆóéòžòéòðóGõßö™øAúªûÊü–ýñý»ýý»üÖü=ýèý©þrÿ†àT†é¾[÷†O3ùUe;$‚ð!ð‘éR¶†ÕmAʽ™Àe¸þüý þåþ<ÆcÒÐ#N3ÃÖÛ£B«à8öÿ ÿMÿýþÞþ«þÿóÿ&ƒò"É­ÙhOý&ú%÷õ ôQôñôAõõñôÂô‰ô:ôôô€ô\õiöw÷|ørù(ú˜úþúIûLûõúsúzú"ûdüÊýWÿ2G\õÙ–Gû—ÿ*Èþ°þ„ÿ8Ì5^Y2 b Óamö+ëqp ðþBþÖýþöþ Usöîè!Ë­í…$^zKáe»·Â¹þÿ°ÿ ¾¡|ÿ6ŠQ»ÿØý•û?ù°öëôôóó>ôZô»óûò4òtñïðÝðñàñgóñôNö‚÷nøaùPúûéû¡üý<ýŒýVþkÿºÕ +ÊúÔ„ ¸?ßDBØ®ƒÂ´×ŽÔu ¹ Ô ´ ãd|LÛM:ùÿñþfþcþ(ÿ¡^te¨N¯dÊ~&,."âÊ„zP€q%²<íâc0ÿVü?ùsöŽôåó#ô õõ€õiõeõÜô'ôpóòòòòjó?ôeõ¶öøAù_úDû üyü®üÈüý¼ý¾þ®ÿš‚€£Ÿ=€mr²)’¼@öëårÿÿ¡ÿâŒÂ™5Àÿ¥¨ˆÅ¢Ù€\ãzŠÿÿ-ÿÎÿÕpzõÙ²©_Eˆ”ÉéÊk­u2዇•ÆGª¬} 4É÷þ ý«úøöÃôtô×ô{õÉõ’õgõEõ?õãôjôðóÇóäó5ôºô‘õbö%÷øìø¸ùwú(ûäûÍü4þàÿ GÜg«{Œ<ìr±ßÃf'¹ÿW³l.ž;¸âÀò›ù»çyΘsÿªþ\þŽþ2ÿL€¥(q`Y)$æG«5lc™rF-;hðHrn*žîgWAþIûø,õSó‰òÓò\óÑó´ó…óWóþòòxòšò>óôßôãõåö°÷Nø¥ø¿øØø¸ø¡ø¶øJù¥ú¬üæþ/S&R t ©'ºE­·:JÁéÿ5u14Ú Ó²o€7ÝÇŠ,2Aïÿÿÿ²´ÂÅ‘ei›•æØzGÍy(€$“Öd¿ 3 ]ö} üjý'úõöúôô(ô¯ô2õ9õÙô5ôÌó*óhòÛñ¡ñÌñò·òÌóàôÛõæöÖ÷ÌøwùÝùú úkú‘û"ýÑþdÆFq/sP6$ãD#t[ºÿ!ÿŒÿàÕ㘭‚÷ °êZftMÿ“þmþ¶þ—ÿÛ0Ð?W.ト#0ìãõJC°;›^–5ÀTìu=¦›ÿîü)úø¶öOölö¸öÂösöÇõ,õô°óãòOòBòuòûò½ó‰ôjõ@ö0÷øùßùqú¾ú%ûúûýðýÇþªÿåATÁÛØwÔó³ÀBššƒTŽ_Cõc¬¬ù§àbMö5@oÔÿÉÿÓó3=ihê$ 3%ƒèQ¼ÐNzÈ[™ó^e/õtÔ¿ÿ,ü&ù÷ûõøõ?ö‡ö{ööJõâôwô-ôÒó­óðówôõ•õ.öÁö÷—÷ øføÙøNùµùYúJûnü¯ýíþ|]$c2Y˜*ä [ÅɃŠTØï7‰@ÿ²BXs\a£ç´{Gÿ§þ°þpÿxºt€PÓEÀ{¼)Ö=Ö<VU±FÕØ8Â…¦Ø’&Öy‹PýPúfø‰÷3÷þöÛöö öRõ•ô±óŸòãñÇñ[ò4óôCõ­öøùù²ùªùùtùÓù¾ú"üÖýÄÿ·¯ŽÚè„î¬k»¢ÒÿIM³êÔm±¹åÙ~ù‡pÎàµZÿyþeþüþí£úUMÕ ËbŒQ¤††ç²Vÿ·¡Â4½ïûf]Ó¼þrü¬ú?ùjøøÒ÷Š÷÷w÷…÷’÷Î÷#øhø½øùàøŒøPø/øø^ø¼øùÃù™ú²ûBýðþhë•ü4Â<Ñc ÉS™bŒvþžüžûFûöûTýàþkÅT¯Õ:ÞV'þàM µ;nÿ(ÿWÿ ÿkÆ1„Ü.„ÅË-¬|ç7§"a^xSä0‚WEA‡ œBÿïüû³ùùø&ù ùúÒùÉøÝ÷Ôö¿õéôšôÄô³õ$÷òøúÍûÀü]ý­ýlýÙü1ügûòú5û ü>ýÓþk忀%÷ßÔÐÑëÐò6¦ÿ‰þ×ýþÿ‚ |„=}WÝÙí ììzƒëÿ¹ÿM•ÉlhÖ‰ÝÕÒì:PD8îçAzˆ ?7°_Ui€#$íà8vÏwþÎûÿøtöÜóØñCð©ïð¶ñ4ó¨ô±õÃöÄ÷¤ø1ù’ùù€ù§ùù?ùhùàùmúüúxûûû¼üèýŸÿ`^)úÍ h>Sfa¦v½ôe²¯¥ô4H“F>ø„6Ä›Úù˜íÚüoeçPƒâN„uÓÿoÿrÿ q!V¹ùšÿ¢þ þþƒýý×ücýOþÿ`ÿ2ÿÏþVþþGýüuúäøøøèø½øXøÂ÷÷CöOõ^ô™óhóÀó÷ô¬öø;ùØù%úLúHúlúâúpûxüýýMÿ1«I=8ˆltL)Çs<¡Šuáa°; o¯â¢Œ)Ø Qñ€±ÿ¥þþòý*þËþ‹‡ñËçwèÿ$ÿPþ3þÏþ}ÿÿÿýÿ®ÿëÿ‚¦„•šÿ<þäü…ûUúÃùûý.ÿ3vÿ¬þ ýBûùÀö7õHõböÐ÷Uø¿÷H÷øö·öüö©÷gø#ùúÈú­úúÔùú´ûýÿgp=vðñï°‡BŒ¿U£­à–ÀÿFý9ü‰ü*þf× V !> Ú w 4!ÿ¥ýÄüümüæü°ýHþ¦þÿÒÿmX-0úÿ¤ÿÊÿl.o˜×q`ɇËjÿ$ÿÖþÉþåþ ÿSéšL3¯ÿ6þéüüãü#ýºüµû}úNùbøp÷¾ö‰ö0÷Çø†úûûåü}üû—ù‰øŽ÷žöºöc÷øMùûüŒüü=ü²ü8þ»ƒ€ðb , UNL•Ïþoþ»þŸÿkÚEdû : H ³s‰Ësû.Ðÿñÿµ'ObÌôéôs…ï³`û²—Gÿÿ ÿêþ¬þÜþ@ÿeÿìþ<þÝý)þÛþÿK/tâoÜêÚÆÿLý,üxûòùPøÝömõôVó/óóAô»ôöOøÅúJýuÿ–³Rÿhü–ù%øgø£ùàúýúÿ…ªÊu½ËÏÃüu ˆ è - cU¢bÀ±ÿ5ÿîþ ÿÓÿ†‰Á{.Ì_#ÿ·þýþ:[{ò¤5‚ÿÿ ÿÿúþÿ´ÿ¿qA9ß@Xÿ6þiýèüÈüý9ý˜ýúý-þbþÚþ>ÿ™ÿÛÿØ0«×>©ý‚úøPögõ&õnõGöò÷ÃùmûQý?þdýdû²øýö÷™ø úyû—üþÍŽøŒ $f^¥ñ X ‘íÔ › ËkHþWüÜû”û¯ûfüšýÿ¢ÍaeóØløX#áÂc©{ììÿêþçý/ýŒý´ý™ýìýeþtþCþXýÍûIúvù‡ù¥úµüVÿ£0§/šŽþwý%þ( ÈP>þ¸ûùOøøøÿøÎøàøùúQùWøE÷ŠöÕöð÷vùYû¸ý²<X€m5ûÿEkâL 1 è¡ ¿ ,³†Y}*wÿXÿÏþ<ýüßü€þùj$¥W×3îÿCÑ©ºôF*TÿNþ%þ-ÿ©M)ÂIÀüÝúnùkøø¬øûgþ;^7æ(Œ®Cμ10Bÿ ümúúÆù…ùõù©ûÝýSÿLÿþ¶ü’û:úIù3ù÷ù"úÓù5ùžøþ÷ãø^ú üÇý“}5? + r   Û‘`×T‹£Áþýü*ûú…úfû ý€þÿcÿÕÿ'u„õÇ×ȶþ?ýÃüEýþ|É+¨ŠŠd··“ÿ¸þKþ@þÿlf´,\¯JœÃÿ©Sï‹= € ¨ ±(Ò†þïüœûû=üØþc¸/êÿÒýýFýjýÜüóûûèù'øÔõ&ôäóbõûö}ùKü¡Ä Ü tþß[­ÿÉü'ûÈûŽýÿ+ƒÿ~þý&üÛûÈûïûOüHý¾þª¿þWýü#üíüÎýØýßýšýîýÄþqÿ>fÉYÒÞS·µ÷;r«A;;Öp`E5íÉ… £ð±XH®Héqþ;ýçýèÿJ«'þRüªüdþ¹ÿÓÿ8þýMýöüÖúÃ÷­ôŽò™ñHò’ôeøyý+d;f6ýW1þªú+øO÷ñø<û½ü€ýiþ­þ?ÿsÿIÿêþ€þaþßþ‹ÿs®´¿šÿÿ©þþýNü«ûsûü:ýþžÿ £€lµ‹‰®FÌBõõÈkX;º8cx,Ë.ÕÚ­éy)«uÿþqþ%Luýêû»û+üØü'ýäüýôýñýÒûGù0÷rõtôžô$övù³ýk¤5¼< Dÿüƒúú0ûáüÀýYþ°þ}þÉýbüûKú!úëúüýðþYÆ„Ôþ@ýœü…üúûµû¯ûüÏü¸ý/ýáü—ýBÿ3¿ºÛ÷|7’Ìî̓ë ]Ïþå÷\¯Ô]¨¸Ñ¤FMu‚ÿÿòÿÊ»ÿrüªú™úLûŽü:þÿöÿ>,üÿ9þQü:úBø ÷føÚû•â>2  ß&ÔÿÜúMøøíø}ú§ûìûÖûûšú¤ù²ø¨ø’ùÕú›û…üãý;ÿ©ÿIþ>ü—ù$ø‹øFù3ùÓøRø øÃøù™øBøÛøÔùòú>ü;ý)þ~ÿvÌàT¥K¢sN¤’Öp F L È { Ë ‘mÛ[î0 „ # ]ÿ¼œÿ—þÇÿ¶ñU 8 ×ãqNÿ¶üû üÞþ ô* Ç„(l†þnûðøkøEùzúÁû¥ûyútù†ø÷.öföæö¡÷/øøá÷ð÷ø(÷Mõ+ó¥ðøîrïdñiòÄò¬òÌòÑóUõK÷åùbüzýþþ*þ¡üðûüÏû–û‚ýu-”À aáQRÚÍéáà § 4d§R Z N ÍÎàä " 3 † Í  ˆÞn q‹[·ÿ3ÿÿ…ZTÜjš jKºÿäüúYù²ù­úû=úùö÷`÷ø5øyøVù™ú–ûJü~ûúüøé÷%÷øöçöÉõFô‹ó”óˆó‰óÇóºó†ôØõq÷’ø†ùèùYù»ø»øŸùúüþ§ÿí$æðs&'U"—çWZ{%ä O % °  ø,wk4ó)Jõ“ÖsÇ«ø ºµd<ÿ£ýŠüdü½ý¹ÿ~ó%DÓÇ  ÿ«ýÂüýþ3º£E©ÿ5ÿòþsþBþˆý¯ü·ü7þÕÿŽõŸ‡ÿGþýtû}ù ÷õôßô<÷ßø±ø#ø­÷\÷÷¥÷‚÷ï÷Ûø¤ù•úÛû^ýËþßÈR1h7”xI—Â~5ªEfµ^ ·vVÿ‡ÿ=ìiwÿF2úf;Qúeÿ7þý6ü8û[úû5ýâÿI¯;K^Ö³‚þü=ü’ýÜÿžY‹8éj¥‡âÞ"çXÛ3à!ãÍÿ^ýüúEøõôõ÷xùLú1ú ú*ú%ûûûúTúßùùöùÑú%ûÁûüýÇýœþâÿùå|­K:OÏÉ9Öÿ—ÿOÿèþ…þNÿ2CàôèÿÛþ¥¬çñlíU˜ýýú“ùÛ÷)÷Û÷$ú@þ݉ L ¡  æ~aýJú±øxùúzû†ûIüÒü—ýªþIÿSw¢Pk7‘¬i¬xÿþÊýÀüûŽø÷Ø÷¼øIù‚ù±ù¼ùmúû—úù÷TõõüõW÷8ù´ûcý“þ1ÿÿDÿÿ“¼D§ å Q Í Æ ú Ê‘rV­þõü9ýHq/—šR †öÇ"¾†%ЇòþýüüšüëþW?Œ < ( CŠ&ªü8ùÅ÷Ý÷×÷«÷Gö˜õöá÷+úUüSý]ý{ý7þÿ`ÿqÿÿþèýÒüÃû­úGùò÷»ö‹õþõ¯÷»ùEûbüLýý|ýþ™ýûû·úúêù½úüƒý™þüþÿ–þËýáýwÿã¯d¬ˆ n Úü  :÷FN™áÿ‚ 8-`T}/éH~ „¡êëþ«ü3üœü¶ýëÿÏ KWf*ÿ ÚZÿ»ü4û‡únú.ù·öõëó{ô5ö™÷mø1ùúqû-ütû#û$û‡ûÂûÏüàýyý3üFûKú@ùäø¡øîø!úBûèû¶ü†ý°ý}ýýÔûÜúáúÚûíüþªþ?ÿ-m{¤‰ÄšéÑ ñ jïѲ Í Áœ®‰ÿâý¬ýOÿ~HÝhdI ѼE^Àÿßüú[ù°ùÐû´ÿ‹àª¦!g·ƒýSû úúDúýùø1ö õ.ô[ôLõsö£ö÷røúùXúû+üàüÉü#üÒû[û2ú"ù÷xõ·ôö÷÷fúìü÷þgÿõc<ÔþÂý‘ýcþuÿ­5 ·v©35æ PSð ¾ YC~®á}*^áZ'=Ø ´ÔÃv€¤ýûÕù ù±úòüãÿuØ>Ì,ˆÝþFü ûoú¢úÙúÐù£÷–öÿõ~õgõ”õKö’ö‡÷¨ù»ûü³ýKþWþ5þÞý)ýìû‘úMùN÷%õaôõ»õŽöøOùúLû¥üsýÁýåý¼ý*þÿ›5V‚8m\ º m * 0 óçm®¤oOÖý  ‹O>+¡ïØÔºjÿ"ügûGûNüwþ@®´ÈS›%ÿ[üÄúúqúâú¬ùP÷´ö¶öÕöY÷A÷!÷ñöô÷þùÀû›ü»ý.þ—ýÊü+ü ûÑø;öØó(ò>ñ©ñ&ó®ô¢ö¶ø†ú ûÛü©ýþêýAý²üãüÇý‹ÿrsž-ŒzÀÿ«ÿ§.Àä † 뜀·Æ ‰ S¢O €w„ £èªê6 5 c Š[—°=ÿýbüÈü'þEàk r  ý ææÔýÂú ùTø!øÔ÷öçóùò#ò3òÿò*ôõöç÷ÑúGü¸üŽýÆýýæü³û˜ùaöþò?ðî$í`î>ðòéõnùOüþ5ÿ#ÿcþxýüûéúû@üÖýõþbÿG{`ÁËT ª üs¶_Ü • ‘Ò'1>”?hOÂá 8é Ê ‰ Ù þŒ”×þ=üŽûü„ýõÿþœ! ô A WÕ¦DþõûÈú8úúùX÷Æõâô_ôô4õäõ¤öø’úý0þÖþýþ+þ­ü;ûùiö ó¿ð¬î'ízíïUñôåöjùûgüMý’ýý7ý€üjüåüþ…ÿ»w«3}™°€T)¸ à …OZ ° ÈûO½+=-Ê – Á (-eúìÝÖ•! ÿ@ü û‘úûIýèÿ¶ M ~ b > <üúíø·øÿø–ø³ötõ­ôÉó¨óóó~ô„õ3÷íù5ýÕþ'Kÿïý=ü*úŸ÷-õBò‹ðïDð9òô)÷¤ù´ûÍü¿ýþ™ýÀüŸû&ú×ùGú)û©ü3þ@ÿ5‚âsáXc^w 7N5…5 ò ìj<‡E  º p ˆñƒŠVp7,ÿ}ü|û>ûüÒýŽfÓµ d È ö»›ÿûûújø[øžød÷õêóÿòóªóuô"õïõ‚÷Xú«ü¦ýþØþsþÑý»üùúbø¦õãòùððÇðkò{ôûöSù ûaüCýwýJýý\üjû—ûtü×ýÿ’$±…Fƒ‚´Ê7  ¹¾nI¬ã À ×Ì'åhÍÇs õ üÁ- ‚ € S G X­­G2ý~ûûüûðýŠW'¸ ” p zÓ¨þ¬û úŠøvøKøhöeô©óóó~ópôTõö¯÷fúüàüŒý;ýçü8ü û\ùëöô×ñHð»ïëð®ò{ôïö ùÞú\üýýËüüaûûmûBüÁýtÿyœ™*qšnñ¾ êk@«y ¤ ° õ jÍäÓ| ¸  » hf1 n Yø¯…-×üûŒúuûýXÿâØ þDÓL—Utü`úúøRø?ø÷>ô[òeñ=ñò@óéôÿõq÷úäüÄýþ þ^ýTüûËùˆ÷›ô±ñŒï÷íßí^ïOñ¼óŠöùjûGý4þ“þXþÁýýâüsýxþÀÿæWÄlMÀÐÚ¥ è ¨g㊒¡ “ ‹ ÌSìËŸ d 0ç^»j  €Ú½Öÿ(übúÝùëúßüªÿDþ´3 ¡Ú¡[ÿŒüÞú¬ùeùÓøAöóñ·ï=ïï$ð*ñµñ¸ó­÷üùû0üjü}üüŠûúo÷Íô¿òñÛï ð òÇóõõ\ø±ú³üòýÕþÿ{þ8þÅýÌý'þòþ+¡–œÜÄm]#] ¦áZ·ðj ~ ó ¯ÆšB Ý B¶ aÁý b  Y ovÛÇþüû…ûêü5ÿB¬2l9è¿ÿÕûûøá÷P÷÷¨÷ ÷Äôóòáñ´ñäñ=ò'óJóôeöeùeú¤û©üEýfýæü«û=ù'ö5óìðOïXïðòÙôS÷ƒù¹û@ý\þHÿ™ÿ´ÿ4ÿ$ÿVÿ%Š?+ 7Ùl£½SU   §@” éG + jÝ%Ì” ü a c ¸i } ½ G ? ŒÃŒ±ÿÂüÂûHüŸýþÿ&°ˆÚìë]ÿü8ú,ùøt÷÷dôIòôð…ð:ðPð:ñÅñJòšô$øßùûü¬ü¼üLüæûúù÷ ôàñMðÉï…ðÚñ>óõF÷êù5üÎýÿÿŽÿ´þPþsþšþ_ÿDîÿŸÿ}ÿëú0œ9ÿ i!iüÓ†§ ´  Ç§Ø ¶ • Ô Ókw/ Ö î Ó ™:غÈþ ýØüzýÿ“XÔ`€úäÑþ]ükû‹ú«ùuù§÷õíóùò£òòòPòzòGóðõ>ø]ùûéûÀüÛü¬ü¬û-ù3öSóPñ÷ïùï¹ðò–ónõM÷ùiújûÎûNü%üüªüný­þTô'O›Î[¥‡'u <ì9µ ‚ D o ØXæ“ ³  R þ.¿Ú  ¥ & ¾ âµúþÞýmýñþûG¾·Oü~ÁgýqûÉúmúoúú+øžö¨õõvôðóôhô$õ©ö2ùüúÓûÊüîü(ýðüüMú÷¨ôNò°ðÀïtð§ñøòäô„ö[øæùñúŠû•ûfûùúæúDûèûZýÑþ:ÿhÿÿ÷ÿª±h[† * ÷ÑNs ÷ >|¤%§  8 1 ØBçËÈ / ´ z¨µegÿ,ýü¾üþhϘLƒc9S¿ÞþÞû~ú:ú¹ù«ùµøŠö,õ„ôôó°óãóýô¤õ½öøìúüãü­ýÊýûý«ý†üCúq÷€ô ò¬ð}ð…ñ¹ò¡ôúöàøòú|ü^ý­ý¬ý4ýƒüÃü°ý÷þ|¸»§X Ÿ0÷Ĭ Ï ó–šÔ ¡ e †y“äµç ù Í *!ÇYpY4ƒÇ΋»†þ6ýÇüšýfÿ ‘x& eDµVýüRú.ùÉøÈøÁøýöªô óŸñTñ ñ.ñøñéòTô÷ ùûü"ý;ýÈý–ý=ü×ù¦ö´óÇñ–ðöðTòSôÁöƒù ûeý ÿ¢ÿÞþþnþqÿ¤nŒúý<MšÑ»¹à K â]޵ § yŒµ; ò | äÿR2ëïLþÿü ûÕú‹û”ý†Q­m=†Í¦þ¨úÖ÷ôög÷û÷“øm÷ÚõzôÉó¸óZóŠó9ôÞô(öèø™ûòü+þ5þ þþ¬ý*üÆùI÷˜ô•òsñ°ñéòfô‘ö¦øLúüËý•þ¬þiþÐýŒý\þ†ÿ5DLyÎÅ1ݼ6.  I£ºÅ¬£ ~ w|AÍY“Mº C R $BÌ­yœV §ÿ#üóù¹øLø„ùÙû0ÿƒY Ǧó"°ÿcû…ø‘÷é÷dø=øöKô'ó{òÃòò ó³ó®ôºö<úýþ@ÿ\þÏý†ý¯üÒú8øßõèó°òÎò$ôöø-úùû}ý“ÿEå’Ô”ÿÛþÿŠÿ@}â—ÑšåŒ Ø ­p™¸2' c  ;E‚ïÚ ™ ø¨-ulþZ!šEŸþCü»úúÄúïü@ÿŸ¸»Ò  ÿÂû:ø^ö öÛöÓ÷Î÷¨õïóóó@ó:óÁóEô6õ^÷úAüýýÀüü]ü=ûòøöDôÅòîñ`òåóßõÅ÷úCû­üIþýþ0ÿŸþþZýýÂþ±jy]+ R¤œËh » Ÿ(Òãe S û Óv‚é­ ª k ¾ î;Y ¹*/nÄ™ÿmüúÏøGùÚú.ýg»í‹®ÛûkøööÍöF÷õõ–óòñlñjñÜñyòðòfôM÷&úˆûZü!üûÅú0ú²øgöñóóñˆð±ï=ð¼ñrógõˆ÷ ùáúµüïý\þLþ»ý?ýŒýþçÿ$êîÒxÔ8N®Ûú Í ÒcTT÷V 2 õ ¸>ýxÃ{ à ¥ çé#‚ ¥ i ‰ ²8­þòü}üGýÓþòU”àó™¶ûòý–úBø7÷w÷ø)ø'öeôóÊò°ò(òLò$òúñßóÜöêø ú½ú/úÓùúù±÷$õ ó ñ©ð¦ðòÊóõÈ÷kùæú‹ü¸ýAþÒý*ýñûûøúoûÌüÓþïÿ"dÌœªzª¼‹c MKAh{¸ ° X Ôpïp( P L Z ¯«Ïéõ e/?ûýWü³ûTüôýV2 ˆ ¶ wvYþcûÐù%ùiùxùpøözô3óDóò”ò²òvòónõ¾÷ËøDúÉú©úäú6û_úYø;öômò;ñOñò&óÎôÏö&øúÈûý„ý£ýcýªü‚üçüÂý•ÿÞŽ:ÿŽÎüàMâ ò ¦½ó › ® Ò­Ô¢Ù j r Z ® •WI 8 ŽâĆÿ¤ü‚û¼û¥üÔþ—+ç:«œ(Aþøúù ø9øLø9øHöŽôþòSòÒñeñ>òËòÌó|öáùäûjý|þ5þQýÄüû\øƒõó%ñÁïˆïƒðáñ ó©õš÷\ùðûþQÿèÿúÿÿyþuþ¼þ±ÿEâM¤cEv#N “ ö%aÈÔÇ Ô ›[\{d" 0  ´ ²t¦å6 U ¦Æà„ùçýüüüþ’t‡£dSŸ¡ÿìüSû‰úwúØúRûúøªöfõõäó†óIóîò8ó|õæ÷ù†úîûBü9üü›úÀøöô3òäð6ñgò3ô²õ§÷Kù1ûäüÔý+þþýýýäüÅý—ÿ†gúì›$YÅé÷𠆜sTð g ÖÊ7Õ4­­ â ² å ¹ @ „ Í  Ù £ Ùtˆ5ˆþÁýòýÿˆû¥§d8Âîÿ]ýíûºúJúSùuøñöžõµóóÉò|òíò«óDôŠõ„÷ùØù”ú|ûsüƒýÚýÇü‹ù©õVòðÈî¬îï ðÖò²õÚøÖûÜý*ÿ¨ÿ­ÿVÿPÿ²ÿ%Ðx‰d4 WOÍS-¨Ú  ¿¾uÞ É w¯âL³ ^ íã   Èä—~Ÿæ‘ÞÄAá_âŽç ÿŒýIý.ýìüãû0ú¢÷Mõ„óSó×óõ¥õèôÇóƒóWó'óóóô‰öú|ýuÿGÿrý4úêöÈô£òRðÂîTï1ñôÚöÝøVúüíþyääÃ%Àq¥^Ák›¨ÄëüÜ Ö ï /I`  . eÍ0§E- – 5 è Ù W – ˲?Æ®` ñN.ýúâùÚúvüþþàý ü ù]öôÍóÍó¶ó+ó\ò¸ñ¡ð¡ïHï ïïöðCôÂ÷“ú»û9ûúùø£ø\÷ÔôÐò÷ñWòô¨ö‘øãùèûËþ»µD„œ vÖp°ªÿUþ4þ§ÿB®´R ' ™ L f ’  (Ì*oÏ^%D‘ º ÷ ¢ ¬ ÷ î . , òØ5p ï“^׎†`Êü^ú´ù¿ù®ú¸û¾ü÷ü¹ü ûPùš÷ÃöIö|õqô óLòðôí­ì@ìqíäï„ò×ô„öd÷§÷ øùfùnøôöPõô¦óýó_ôiôCõ¥÷bûÅÿ̶8ë@ ÜPîø Íä.’:X ¾ " [ à  ¢nÒ%{h ¨  Â Ø ƒ è Þ O Q ë“ýêû + é ²¹ý*ûúÂù¸ùùÞøzø#÷µõÝôeôðôõ­ôXôôºòfñ\ð¿ïï½ðcò;ôÐõUöÔõSõÝõÓörö0õ|ôðóâóÇôÇõÑõÛõB÷Êù-ýÛ& ÞcL/äcŒþmý3þÁzm‘  ö  . m Úû(Ù&Ä ð i ` Û Š „ ‘ c › ä ± á p  t”3 Ù _ ï ' ‘6;~ý#û(ùº÷Ðö‰ö÷÷öGõ)õÕõUö=öƒõLôòuï§í)ìÒëùìÓîXðJñ”ñ~ñcñ*òçó¿ôõyõkö÷Q÷^÷¨öæõ#öV÷`ùKü©ÿxÚ´éj³í(C~’¶nØ—æ¿ ™ y ·vS¦f|…q Ï ’uâ†ÔE   Œ 5 N 2 Ñ© .¥trþïüqûCúêøÛ÷þö€õµôlôõÝõQö,ööÜô´òDðþíoìZì íŸïÒñ.óŠó3óóØóôtóÏòoò”òÂóõÌõÐõöæö¼øFû¸ýÀÿ}1®±¾újg¯‰ÿýþfᾆz© Ÿž»½À 7  Œ ã + Û sÎ÷ÚqÖ†  ] U –2 † ° X¡€ 7 µ'ÿýÛûòúˆúXúxú(ùš÷cöŒõõwô¦ó*óAò¼ð¬ïpîIí=íDîzïÐð¯ñGòÌòöóßõ@÷÷öpõéôíôPõÞô,ô:ô{õæ÷ÿúõý“ Xw¼š&cÐÿ‘ÿ]KÙü C  hðŸ0è M Y Q í § «’:6æ p £ ì ” v ög { b kÑWÚ M½26ÿfýÑûxú|ùªùù8ø÷©ööõ¶óçò–ñðïEîæíœîEð—ñòÁòZòÕñÎñÃòÊó:ôTôŽôóôÄõ¹ö¯öûõiõÓõt÷0ú1ý¨ÿ¯b q-^@‡SŽÓÎÇ«0;òþˆ ; ç «Ñ)Ñ o ¼ ‹ &䘠E ¾ § ² \ 9 Ð . ü O mÜE Õ Ö¿ÿQý¥û=úùù·ø-ø øwøÏøhøv÷(ö6ôqñCïŽí€ì¶ìpîIðêñÊòâòFòüñÀò”ó óYó€óæó¶ôö•ö*öoõŠõönøÝú$ýIÿWtGr*ccºÿ¢BZ3’‘\;5ŠK§<Õ=r.ý ™  Œ v4äºIß Œ ò¨„’ ÿ *MqX 1î Iþü×úÇù¿ùzùù²ø»øøød÷ŸööôWò)ð:îÕìŸì´í(ï´ð½ñ*ò;òXòóaóÂò»ñññ¶ñ¹òbó‚ó´óËôµö0ù¬ûšýWÿíÑwMž²g¢K!Nì?+h.,  ç 3Ì*ež ·  _ 2 ³ýëR†5Õ^ n X B k Î o 0' G+ÊØ…þUü úÛø‹ø®øÖø ùbù_ùøã÷1÷uõ>ó¹ñgð—ïÑïîðáñBòÃñãð$ðJðeñ!ò ò»ñ£ñøñ¨ò{óóó·ó²óuô5öø¬ú?üÖý(ÿ ü nÈE6` ¬jÇ_h+´\Üèw _ j ÄŸãI -h`Ë ¥ … s ‹ … w x £ F ¨@½‡Á†ÿªü ú´øZøœø#ùÌùrúúöùöø:÷ô.ñ¶îíÔìðí¥ï?ñòèñ-ñuð~ðñvñÔñCòó@ô”õ0öö/õuôÎôJöVøfúpü‘þÖ™®NŠ®;gâµuª”Û±¤q´œ{ œ À 0  ô ¼ LÞ„ª¼3 ¤ q Ì Ô / Ä Bdä’ Ò ¤wÙì¼þÜû¼ùbøŸ÷r÷B÷úöÉömöéõ¿õµôóUñ¹ïÅî²îLïÞïð¾ïïGî-îÕîµï,ð"ðNð ñòáóÚô'õðôõô¨õáö@øVùŽúïûþ~š,¿ë=F­áànkg.(;ìÄ€- Ü  Ÿ ý z!-Ó ÎV‚f ä S à 5 { D ÆÆ 7 "_ÓÝ3ý%ú€øÃ÷Ê÷øMø@ø¸÷¼ö”õ×ó~ñï î\íôílïÿð6òsò—ñBð(ïÓîWïáïFð¤ðsñ¼òôóKôôóbóóKó¡ôföÁ÷üøú™û³ý™ÿùÕÆ}›ž=¼Ô$‹dç]cÞ & ¾  —•3L‹1;½ H ~ < g ´ ¯ 3 !‡§¯¶ ) ½ a µÊþºûùJ÷šö—öûö÷õöÂöjöÆôó#ñ’ïïÍïûð#ò›ò×ñ8ð|îXíëìÜìšìeìØìwîßðÊòâó^ô˜ôõVöøGùçùQúçúnüþRÿÈZØ»‚µ^žçµyד‹åç÷ T L¶ù âDŸ){@ì n × ø Ž D\Ž 6  3 ÔŠœG±þ\ýªüèû8ûú¤ø%÷ö2ô"ò„ð;ïÐî´ïIñmò óÝòÚñtðrïï2ïï©îxîâîðšñmò¯ò±òó6ôö­÷hø­øÏø—ùûküTý<þ_ÿuØ¡sû‘«a®“t&P¤Š½ÿçÿß„¬fW +GIÝ5²åÿ †  + i Ðàã© O Ì Ì ï ‚‹àÿçýøüTü#üÙû#ûHú†ùøOõólñ¦ð5ñîò¥ôÝõîõØô¸òUð°î'îîî î¡îþï·ñ÷ò—ó‹óSóÞóPõ,÷§ø‘ù ú¾ú5üˆýþ9þYþþzþ.þ$þÌþ— C÷Å¢+íP¬4­Üz¢úþ © :=êz©Ü: CD½ 3 ± ¾ 9\Y= à ­ 1  ¿@{jêþúýBýÀü÷û@ûŠúú*øöaô<ó¼ò(óôñô4õôó½ñ½ðð½ðÅðˆð–ðXñ±òøó»ôõõeõ}öGøÀùrúÛúû^üþ ÿ˜ÿa†ùÿÿªþ<ÿ÷m(°ºØîæÿËþŽÿ†0ðA5 Z À42L;£Ñí i Ï % Õ  | Å ® I ê 3 É)´×!ÿ+þ.ý;ü8ûÛù>ø.÷¬õô*óŸòûòjôödø{ùùG÷øôó²ññ¯ðkðHð¹ðùñ{ó‹ô&õoõÊõäöòøÿúDüýŠýZþ¯ÿ‚¸îH‹1t¯ÿ¨ÿ¶ˆ˜°ý; ì,PâÿQGáêDŽ H óáK«K˺$« P R l ; ¾ Ìѳ3c % E  Qk"Ìþ#ýüqû#û°úúùøÎöïôtóSòòó õ÷ˆøðø øWöqôÆò„ñtð|ï×îÝîáï[ñ®ò}óúójô<õæöÈø÷ù½úEûîû?ýŽþYÿ»ÿ…­lOÒ2K`am#Æh2ÚÿæþÖÿÖ¤™v†` j WºÈnÑ  I o — V ã,Nà ž K à Œ Tèu€.ÿ?þ\ýkü?û­ùBø¶ö<ôòšð»ïôï<ñÒò+ôõô¶ô³ópò}ññòðÎð€ðCðšð{ñ‘ò<ó‰óÂóeôÂõÕ÷qùdúüúsûüþýùþˆÿóÿ0:¬ÿ7ÿÿÊÿŽß«:…òøßý¢ÞÿÐÿ†JHünâÄ ¥Él;‰¤5ügj„ ! œ » × ? Ð Á … é à ¡  Å vޏYÿþý˜ûåùøÜöêôãò³ñPñôñËó4ö øÉø"ø[ö!ô!òüðDð•ïÅîIî·îÑïúð•ñ­ñÄñ6òwó‰õX÷'ø¢ø&ù!úñûdý þŠþÿ.ÿÚþLþÇýÍýYÿ¶ëÌ?ý¿Å¢³¿4rüž˜Ñ ¬ ý2•Òøj. ¾ ]þ*{ × V Ù € ’c¶¤'ÄÿhÿiþÏüÓúKù÷ýóÂñCð!ðŒñ7ô¿ö]ø§ø¡÷ÉõÉóòŒðøî¸í"í—í×îsð¥ñOò¤òóÙó?õ´öF÷A÷T÷Á÷ýø]úûºû¸ü¡ýèý}ý<ýyýíþhÈ©phžª~æ:ÏÿyórÍÀY„ " ¾ÎiICy\¹Ì1  % Œ Ó _¸Úêõ  è  Ì §—ÖH£1Èÿ#ÿåý;ü¨úùIöÚó ò ñQñîòØô@ö­öèõô`ó]ò³ñéðóï'ï²îïîï»ð6ññõñ×òyô´öDøÞø,ù^ùYú¿ûjü‚üÆüÔü£üÚûûªú•û¸ýVÐnSÓ|…hÿr‘9ÀéHÓ] } Ž Ž©tâ¼ë ó  Ä 6Ì1± Ç + 9  ]­|ÿÐþ†þÌþ˜þ½ý¨üÀûôùß÷sö”õ’õ£öRøšùúôøÏöôÄòò¾ñ.ñ¤ððñQò£ó1ôÙóLó9óíóƒõ÷X÷÷÷¼÷cù¶ú+ûŸûRüóü ýÉüƒü$ýÿä53u"l3 ÿœþþÿ±Gd}¶ Ô eÌÄŽ Î z J S Û Ð Í O ö â Þ ˜ ` ©Ùw…‰[ÿ¦þÐýü ûùù…ømövõ4õÕõe÷àù1ü•ýŒýÜûPùãö@õiô~ókò«ñˆñ?ò™óÂôXõõ²õiöò÷~ùèùù'ù6ùZú~ûüû!ü¶üNýYýüÖûÀûý‘ÿéíÁÄAŸ¹þþþÿØ–´ê3~  Ø cÒ±Sš ° d foG L ¿ / · £ « j î IÔ†^!ÿˆþØý|ýzüïúYù>øDöVôÇóvôöBø'û:ýóýý#ûüø,÷öBõôíò+òcòeóôNõ­õîõÞöqøžú>ü{üü•û¹û;üˆü?üFü­üâü]üžû]û]üþGK­HØñ“¶þÇþ¸W@ k³Ó £ ¾ è<ì $ µ ›;  R y ã   1|³þ§ÈþÇý3ý¨ühüü„ûØú~úkù$÷‰õãôêôïõøfúËûüûŽùøg÷<÷uö;õô`ó†ó.ô»ô†ô ô1ôjõÆ÷súéû5üdüçüKþ}ÿºÿÉÿ7ØÿÈþ®ý%ý÷ýßÿÊ¥ÓŠ®ÅºÆþëýŠÿ'ÒZfc f 2Éyy  " e¦ ¹ t - t‚ É f =ÐOxŸbþäü¸ûÝú^úLúúxùúø]øðöPõÌôäôõ÷5ùçú…û’úØø ÷åõÄõ¡õúô>ôèó>ôõüõdööõ…õön÷Éù—ûÙûðû9üýQþÎþ§þéþ¨ÿ‚ÿjþ¯ý þñÿUáàff©~! Yþ¿þzdª¼0 õ ì¡ 7n’Õ  s _ õÈ  _ ¡ Jo Q 3 ¾_ÈRBþˆüzûéúxúhúsúêùù{ø‡÷Æõ»ô}ô®ô’õs÷`ùú€ùÇ÷ûõeôæóHôaôjô¨ôOõ†öà÷èøñøMøé÷aø¨ùJû¥ûûÜúðúü2ý¢ý(þÿóÿWéÿa—žIà‹„‡6ñþÿý•ÿ½ùßr  Zåç_f$B ¡ c \Âß  Q a V ¬ p $: .|RþúüüLû»ú¤úúþø-øw÷ºõÊóÖò·òyóFõ ø)úüú-ú¯øèöxõ¶ôÎódò|ññÇñ<óþôøõööúöØødûýýõüôüÊýXÿ&' ÌÿQÿÿéÿ ¼ª5<e>_,nÏõ%NQ¯F % û {=ŠŸ‡º ” ‹ «L¿ $ W 2 Ž ? û ó ýá|L´þý—ûiú|ù8ù}ùùxø ø÷øô–óîòåò·ó»õ1øàùúGùÏ÷>ö‰õuõ™ô¢óÃòròÄò¦óšôªôuô õ³öùpûVü:üJü³üòýÿÿúþ^ÿ¦ÿ|ÿ¿þ%þMþ1#øS‹Ç-ÀAภÿ¿Ç–ü‹ Þ ìˆ{æz$Ç ¥ …K^3 Ï d ¸ ¡ ¦  æsÖuhÿý±û"úÒøà÷Pø~øø‰÷&÷ öôóþò[óô2öMø>ùâø›÷5öôôïôñô1ôkóøò óáóïôeõÕô:ô„ôöªø û&üÄüýþ7)OY:ÿ¤þ3ÿðBQNõµÆ8!Aů¦Ò$ 5>¥AÒ Þ º vI ¥ ë  ¼ sW)Ì2Æþxü©úúø¤÷3÷Ô÷ø¹÷\÷@÷(öãô1ô>ôlôõ»ö øøúö`õÖóÀò"ó+ó|òáñÙñÎòSô‘õÚõ4õžôõ¦ö‰øÛù úWúÿú“üþÿèÿg ;ógk‹µÂm`œØ0¶ŠŸUÏ!`Z` » m‚³büw¢ D U£¾’ R ã “' J † ¹L¨„þ5ý!üUúŽø·÷Ð÷¤÷,÷÷ÅöõLôô"ôhôŽõ\÷kø?ø÷µõôgó ó;óòwñpñŒò÷óõOõ©ô|ôˆõd÷^ù<úýùíùmúÇû7ýçýkþTÿtLòÿÊ}HlZ¸èý-*½TwÙ‡' ³ d ئ,(eü – õdÿû Å H Ø ’ R?»»ÓÞÿ<ýtû˜ù­÷]öxö÷øö¹öÍöËö§õÐô´ôõMõ`ö øùòø÷ÒõñóSó…óáòÈñ=ñ{ñƒòéóêôõ¯ôõôDöVømúŒû°ûïû–üûýÓþùþêþ_ÿgÿ#ÿ¦þwþ2ÿdgÁ@ U “ † é|32'ä¾ béÆ ¸ÏZåj£X»7û : ‘Ð ^  kfQ € Õ6•Ø=•þHü+û;úàøÌ÷ø“ø$øÕ÷Ç÷j÷ÒõXôáóØóîóÜôCöÚöröjõ/ôóqó<ô¨ó¯ò>ò§òÓóõÌõeõèô9õ½öêøíú²û“ûãû¼üPþ?ÿdÿqÿÇÿ­ÿGÿþêýþ矇ǒÕ`#:g ºHÞ¥ ”ŒÜ3‘»òÀl Æ 3 — 9 « œ2í @ éO~‘õÿ2þNüsûyú+ù-ø­øúøwø-ø)ø‚÷åõõÅôÁôÂôö‹÷/ø¥÷vö¬ômóÅógô£óÌòdòò+óøó:ôµó€óBô!öªøÞúÒûü§üêý™ÿ‚¢º.Dóúÿ&ÿ^ÿFª·¨¡Ööhœ§Ç+óú   –¥£kô»£7 : § Y¬% û  ¹ò+ üüôÿ3þ©üûú°ù˜øÜ÷›øÉøaø ø øR÷óõçôKôþó–ó_ôeõ¬õýôôÐòRòcó$ô?óƒòfòÞò6ô}õÑõKõõ‹õÛö¶øŽúû0ûþû‚ýhÿ–2½ŒÛorä]x2ö•™ ½˜¥ŸÞFËL Ê 0n+Ë4M+Öv  À0  ÷b´ • I)¯$ëý|û®ùÎøŒ÷†ööºöýö¶öÐö÷Pö×ô ôÒó†ó™óºô£õ«õ¶ô,óÁñKñPò²òò ñºñIò_ó?ô>ô‰ólóQôöKøúyúÏúøûÝýÐÿÁ2̯{K}âiIêªãm¥ÐX=ÿ1ƒ[¸  `/‡ÿ_rgM õ » ô e%lH ¹ :…ªþðüKûhúöøx÷ÍöÃ÷1øøð÷#øE÷÷õéôkôéóIóôñôÖôÎó5ò¿ððûðDñhð®ïðêðJòjó“ó%ó#óåónõe÷öønùÙùû¾ü^þCÿ¢ÿJHóÎÿaÿGµ‡×ÆçL Þ Á§Æÿ£ÿŒ;Ň ¤ ö'jÜi”wY ¦ ©;Ój b Ÿ<CVã X HƒGÿ.ýrû¤úiùyø øÜøuùbùùÅøÖ÷ öòôônó!ó>ô\õrõ{ôóò òó8óúñÉðRð·ðÍñ±òÛò¢òªòÙó¾õê÷¨ù=ú¾ú¸û ý˜þ2ÿ†ÿT;\«ÿÿüÿ6äÐ¥¸)¸ûJÔ~ÿŒˆm°Ü º|ë ö¹k°  ¬U < ð bX•^ ð IOÚzÿ›ý=üIû%ú4ùÏøŽù±ùUù×øÊø]÷ÅõŠô¾ó÷òæò+ôNõsõ‘ô‘óµòóòðóôóeò9ò|ò5ó¨óFó”òyò¬óËõ]ø&úûülýÿTÅîvÑÄ‘ÿbÿÃk„f)Ðæ:OÊÿ ̘Ûëª © ò nˆ0衊ãÙ S  5 Ü 9t´ï ô (i¥e‡.ÿjýíüŒüJüÎûÓû>üüûhúÄù ø)öøô+ôóó*ôÜôlôbó,ò©ñÚò¬ógóZóWóWó”óôTôôPóðòèóìõ2øxùúû€ýŠÿ›ÔJÍfÄvÿyÿ»ì[²‹´ÿ•òî¿0µäêü‰ ã œKAÊWõ~ r  <^Ë  _#õgz N {®½„eþJü=û¢úÿù¥ùOú…ûÎûiûûOú|ø÷öØôöóbômõÏõ9õ?ôóhòÓòTóûòRòCò‹ò{óiô®ôŽô¿ôjõ•öøùwùúVûŒü½ýìþ×ÿàÔ , "ÿ÷þ÷ÿ⫤뭞Shÿæþ—E™+~7 ¬ ±  ©,æŸy  ½ ü`ñO Y / I c n Ž’ÓEÿGüÙùêøNù–újûçûÇüEý±üŒúÙø~÷ öéôÀôõÙõ3öáõSôüòÄô1õÏòcñòÂò_ó õ3÷è÷Î÷tùÅü\ÿ":°äd' Óà‘§o<ÿÕû—øÚ÷®ø&ù,ú¥ûõûqüþpþ¨üÖû¡þb£;éÄ. I=ß´k!v Ÿ ‹¦jÀ¹~¨ÝT ÃÔœÝܨFÿWý"ûÜúÛúù÷0öšô©òWñ½ñ-òEò¬ó(õ õèõù÷dùŠù”ùeùùÏøŠùðúüÚüSýØýæþ—ÿ ßœ¼°W6ŒP™¸6+¿»CaO+W¾¯þJý{ûù´øúüùoø´÷<øèù¶üJÿ?]­h f  Y R ¬ ¿´mwÓ”èÔg’4$/ºéÿèþqýdüÌûûáú3û™úê÷õËóÐó­ô­öYù,ûsüRý”ýTý²ü¶û:úùoøc÷A÷qø\ùIú0ûü ýbþEQuÕ›9¹âÿÕÿíÿmÑ,àP^~ 3 ¢  P£€Š ÿ3ú´ø²økøŸöGõÊôòõdøÜûÿ"¡vq T ¹  —öDx Ò×sº”¼äáïÿšÿÛÿÈÿÿ=þýfü”úè÷ØõÆô©ôCõÖ÷lûþØÿáíÚ´ÿþûƒùç÷Åö½ö÷røùúóútüÎýHÿ2}ý·øþ2ýµû ûÕû¾üý£ýÍÿb@v1.£ÀiÿÇüûSûÐû:û¬ù`øóø™úåü]"Ôå Í ì K  ¥ â'ײַÊêt¦ÝŽ`\ãS¬ ª¾ §ÿ°úãõ³ò6ñÃð¯ñô>÷KúIü~ýþ2þGýûúªøáöJõ¡ôÇô¸õœ÷ú\ü@þ~‚€–Ÿ1Ä\ñ2¼þ²ýwý ý.ü½üôþQÁÿ“þéý)þuþÇý•üKü@ý*þÈþþHý¥üÁü–ý+ÿÙÁ#Ê{Æ ‹ + a ’ "Æ t¯.¢”³†Gø$UÆÇ(©«KÿsúåõZòÖïZîïîöðhóÚõ´÷4ù…ú‚ûÅú«ø·öòôOóXò)ò8òåòØómõá÷Òúöü'þ;ÿ…û,S–#ä6 Ì vzµoE±ìïA~eþˆýÁþK“Úÿ¾ÿRW,òRd } u % S å  p ø q ŽÌæ×, °éGV xã7†Žÿÿû4÷Äò³îÁëþéOê¥ìØï ó‰õ÷Bù>úú¨øwöôòññmòSó€ôVõžö«ø=ûcýóþ/N ¤MØDÞ°}$ ÿ5öñ¢ÖdjÿÙ±“ò®"µï"²šòŠÕ ] ã ªR<æ^ O–wjDò^Ú®8ï4xoƒþühùdõ±ðÒìÖé¨çüæfè4ë{îoñÝóãõa÷x÷ƒöEõ÷óÇòò]òæòªóÕômöÏøºû¤þ]*k‹-V ‡‡_W†ù2î/ˇ ‡ t|Ábh¦å**Ç ë r } £ Z À – îuŸ¸Ö5Ñt”}Ie¢×ÿ{ÿyþÜüdûËùˆößòŠï›ìTêênë=í=ïóðQòƒó`ôbô3ó6òÇñâñ¡òÈó¡ôQõ@öø…úpý9Q¨f(   C Û< Q AZ"Ö°Š1Ù\Þ³ „“W0¯ÿ™H®5ràŒ… M H ’ “ ךG†ÞÄŸJ†+{ìÿÿÂÿÿÿxÿ¬þGýÆûWúà÷ôKñî-ëéÒéëñìÚî¢ðYòPô™õRõTô_ógòäñvò¨óóôwö'ø+úªüsÿŒæÖTœS P § m ø Œ  ‰ Ú j ê ù h Œ]þˆZýIð½ßÓó+Öož  \ #³ýe ÂÇ™9¢f,JüWÁèµ»øÿxÿìÿ»L¹fýÿãý û÷$óÓïðìëÀêÃë7íÕîÇï¯ð»ñÿò’óýòòßðNðŠðqñßòˆôöë÷4úSýÒÿ¢*‘«R¥ì.‘ÈÚéæJ z ²åoÌG&W¶¨–[Ïb‘Þö¡ä@ r t/«ý T y›ù¡$d#FïìÖšÝxP­þeúQõìð,íêÆè—évëŸí•ïÿð_òçóÙô€ôGóÝñ¬ð?ðÒðÈñãòŒôÈöQùÆü3º c•æòÁ ¸ Ë0qfO’c:ã€Æ¨ÚýŒƒaêTe$Ôik¬`W L ç ”S @ wœ,eÇKæ]}]:ľ¾(s‰’M%ÃþIùëóï¹ê˜çîæIè•êíï±ðòóhó?ò›ðï2îQîÑî¤ïúð€òô~÷Èûrÿ†(ïkœ«âêY€ÑÁÓJ ¤Wi·ýcÉbìï¤úûh©L G h 1º¢°,’ x KÒÈD>“€õâÿŽ"×ð™Z  áÛiþù1ô˜ï¨ëêqê¡ë=íÃî,ðžñøòó¹ñ.ð¾îií íKíàíïJñ”óörúëýéÿuf¸÷÷RZµ~Åc«¢iꊅH^!LT›+\ÿÓTÅõ¨Zöå  Y Ë …$ù± p _ b›\«Fåmqç×t¹4E ¾ Ù Ô …  ¡=ú—ô.ïRëØé®éŽêIë!ìÛí„ð´òØò+ò8ñ®ï%î…írííÉîÒðCó5ö¤ù…ü?þ%¦R,¼ÔYå/@  ,a:F¼…Z Êþÿýnÿ â@Žb‘Š£)" [ ú Ù¾É B &¯‡¬× J [•šÛ(äi·  Ôà è C ÿúúôóðKï­îZîîí]ípíÁî„ðëðð™ðsðôï/ï¾îÐí"îIïŠñ0ôj÷uúwüyþIoírÅRvÈb3+ÂØÚøÜåö Mcþ ýÔý…ÿ-õþmÿ=ˆÆK … à ®sl· ß ¾tãç©  ž| ¬»”° ò„]Cá {Ä•þìø7ôÐñ0ññŒñPñ‚ñêò¡ôéô1ôkó òÕð§ïï`îhîïñôÄ÷×ú6üþnÿ Êu?îÿå½bWÈ|‹ÿãþZÿæÿWÿVýûûKüËýëþ‰þýý£ý~ÿç߆W ñ ò X ¬ 1 ’B+¢m؛͔þM1šº N A f"¾Ni£ GOü ÷Çó,ò‘ññ†ðÈð;ò'ô‘ôÑó>óºòDòŠñDñÔðñ#òéó—öù<ûáû-ýPþjÿæHTÇsi)¬ÅqïaøÿuþÍý‰ý¾üû.úRû@ý/þ‰ý&ümû­ûýQÿ˜Ió h à D @ —oœiZ£Ëy o®þ¨(µÇ _Ѩ§uw dô—ýØøWöQõãô*ôPó$óô¼õ.ö¹õ¬õ†õºôhó_ò ñ½ðñšó´öúùüþiÿóÿ}ŠÝùoÙ-»jbñU| ºþÐýXýüþùøDùêú¶û;ûÅù*ù—ùûýïþªx}j ¤ A Ùâ ôÿšÿ)‘ÀnÍè׃1í­Ì aÄŒþÒ– +x?þ·ù³÷?÷÷öÖõ¹õÁöð÷Í÷÷øö÷&÷yöüõäôžôüô@ö@øâúÕü¬ýÿ~».ßD% fŠrldÊþëýÚýÐü ûú¢úÆûÐû„ú¢ø—÷÷]ø'ú—ûTþÒZJƒÏ)«ÿ“þžý=ýfýjþ\”9Mu˜M½ù£ PaJ:zÔ í…4ÿLúÅ÷ðöŒöúõ¦õtöNøÐù»ù÷øÐøEøå÷áö¤öøõøõ´öøYû(þ%æ«Y—oH  <  { èþVò î-œÿ´þNüûù‡ùãúëüþÀýþûœú ú úvúÉú ümýiÿ¨ 4þüÑúuùäøöøúdüéÿÐÀª8À0Z~ ç ,!òf |+Áþ2úø)÷}ö¤õõ›õ®÷eù7ù]ømøiøwø¹÷¢÷ãöT÷¦øËú­ý†'Áv¢Œ?K¼|  y o ² , äöstßx1¡®þµüôû£üƒý³ý“üˆû¬úµú£ûõûÜüTþ`ÿy2:ÅÿúüÌùø™ö¼õÂõ¼öóøØü£ÿKXˆÈÿÿ¬Cî † R¿h X P;üø÷_÷ôöö²õaöœ÷vø øe÷Ô÷Ö÷+ø&øyø…øùûý<Iú 4žö‚ Wt Ü e V u ­ ý ¤Äï¡åªkÿfýæü¬ý€þ…þÙý!üDûÞû'ý|þJÿÙ¹Ÿã¿þ‡û`øöÞôÌóôZõr÷lúlüOý=þyÿ¨þþþÇÿ É¢ ¬ i “ Ô Ü BMûøöƒõHõGõ-õõµö?øzùwù¨øvøà÷÷zööåõƒöUøûúZþ®S*^%Ï ’ , ¯ I ¤xÈ~Æý•¥ÁëÿƒNëýüŸû5üªýØþþšòñÁé%ÿ“ûFøHõ'óFò5ónõrø‹úºûÇüþÌýÂüü!þǬ™  â ¦ ·"`xýíø:õôGôqôôLôZõØöø8øŸ÷]÷W÷ÿöö{ööHöü÷ªúþÔCý﹃¬ q , é Õ z I Š?‹áK¥W¨Ý ž_'‰ÿýýìýþkÿœùW©$òl%þ¦ûcù…÷­ö÷öÉøvûýRýÕýþý9ûÊúÈû¸þÜõ Ú Š Ú õ ïa”ü©÷PóEñ1ññûðHñdò½ó6õõHõeõþõNö&ö&öûõ)öR÷»ùÛü“ÿÍJ   ì À ¶$ ò J œ „ô>v6c5}|gú|Ï%ÿxü:û›ü¼ýkþ_2íéö–ê¸òýSûÈø5÷}öì÷žú¾üÇýÚþ)¡ÿßýýeýzÿŒ<~ & À X ; Kµ~ýß÷¥ò ðàï"ðÒïöïìðQòÐó ô¢óžó÷ó…ôëôõ)ötöz÷òù¡üUÿë%ûšÍ  Y º / v ÿ Ï ô A Í  ê ?uˆ°œxMÚ:šþgýÐýÿ(ÿ®ÿ.{åZcñÿ“ý@û?ú‘ù™ú}üÈþºÿ^ þ‘üGüñý<üš - Î ± L›£ýpøóÄðžðñññ'ò§ó õŠõ5ôGó¾òHò˜ñúðñKñ¸òMõîøÈü'ú t•Ëž­ ¿ É @ å s ä r & 0 þ ª Ë ú ¿$L¹ A²ûÃKÿCý¿ýbÿïÿfØÁä³RÿxVþüÖúoúûþ†¦a³jþÔý>ÿ‘ h Y T sNý“øÜóñìð”ñLñÚð±ñ¦òô×ô;ô'ó~òãñ†ñ¾ðð†ï=ðòùôëøóü†ÿ·‚¼™  @ ¼ Œ " Ê  t « Ô * Æ ì  ’A §P âIYð"þuûõúüoýXþ8GÿMÚõpXÿ×ü°ûQûüÉý;YzÛ9WsþÎýmÿÀñ| Í è ñ › ’˜+þÑø’ó/ð­ï%ðâï‘ïDðçñ ôAõ¥ô¼ó=ó#óóšòúñ7ñ„ñ3ónõqø­û<ýŒþP¦¾ù5È d Z  H Ñ X Þ  ù — å  ,|d)¶°´Zlùþ*þØþ-ÿoÿçd<"óD0ÜýÄû¨ú„útû™ýúÿ‹#°1ˆhÿaþ{ÿ‡9Ö l c  K¿ÿYúûô”ñ‡ðGð?ï–îöîÞðóSôÞóqóÁóöóBô×ópóóYóõR÷ÃùRüÖýµþÆÿ½Ù²E ß$ ‰  l + ¯œÊ¶[‚¯CnÝ&q}e€Uÿ`ÿ¿ÿ$^,QÈSËháýrûúú•û þ¡P•ØÙîêÿÓþÒÿÊÍ Â  ¡ Q 2 N®ÿ úFõ°ñ‚ð'ð ïÂî0ï½ð¿òÄóqóèò*ósózóó¦òhòëò¬ô>÷úÂü§þÉÿ¢ikY6hm¦ƒÕÛàE50¸d9iµ bmbÿØÿo7š$H]ÿý¨ûWû×üZÿ6'n´+¨ÿ>ßÚÝ Ù š ’ Õæýøkôófò'ñð ð,ñ’òqóãòòBò«òó;óó„òºò$ôöíøzûýSþcÿloõ%8a¶G8j•\á©1AÂ’8! ¡ šþ£þDÿþÿ…+k’Nˆ'þÛû\úSú3üùþéõyãRˆ¼„;ñß å $ â ‘m ÃhÿƒúW÷þõßô9óòŒòÛó<õ\õôÿò~ò òò)ò6ò|òô¿öúùÊü9ÿ‡>ÓöBÞu üˆRì%Üq™§ú 21Eÿtÿü²|.ÿþôýLþwþ"ÿöÉT²@ÿéü…ú÷øµùü|ÿV6B£bÙ[ÊC) ²vÎ|ªÛ >½¢ý¤ù?÷HöÖôGó²òvóÔô×õFõ>ô÷óËó¬ó™ó)ópò[òró°õ¤øÏû¶þÞXcâjÍ03÷틉n"$!´ަÿ?ÿ6ÿ<ÿ¤þÉþ˜ÿ+  ÿâü•üµü¡übýîþ&ª<t ñý ûeø¤ö©öÆø÷û)ÿæÚtLmÅÚß¯Ø Î‰m©æ> ›_±ýaú¿ø’÷<ö€õ”õVöo÷y÷ËõKôó\óNóaóðòòó‘ô¾ö•ù·üvÿuÒ¾/Ò@³Ö€Ž P Ø 4 @¹U†¶ÿNÿzþÍýþ—ÿ+/•ÿgýrûDû†ûáûšýïÿŒ¶µÚÃ;ÿÛû~ø­õ0ôõ¢÷û<þ>ߢOqTb9 ’PGVNa ·Pþ]ü²úMø÷Áöúöÿ÷xøL÷âõ õ…ôôôóÔòãò-ô.öÒø û#þ¤Ê¿fr1s²³÷ % ñ ‰ Ê è_a]Ä;„øÿh>çæªþïü'ü>ûƒúoûÚý«\ˆÝÍÿ•ü¥ùösôZôÿõ§øHûxü˜ýƒþ6þªýxýÄþú£y  ‰ @§'ù ü<ÿmýûtùûø ù•ùÃù‹øb÷šööèõõõÊõJõ^õzöí÷üùüíý%ÿ_‘¸;+Пd’ ] ù n Ó ½ ÒÉi(ËÀÿ)ÿT½e(Æ~¬ÿäýõü¸ýÖÿÜ&rÿåûíø]öüóòòYóIõø úûxüpüÚûû8û¾ü—aH  Ÿ »”c Ù>ogÿoþý\ûAú:ú†úCûKûˆúÔù<ùåøŸøø?÷hö­öø¡ù¢û¸ý@ÿ,"Ydi]€ßÍ  ü  *oŸ~§ÂÉÀåZ ŒŽÿŽÿ ŽoÌ,;ÿyûRøxõóBòcóõ-÷4øæø&ù†ø¿÷ï÷Zù£üÉ„ï ï „ º×Ó ®   lÿøý¦ü¤ú.ùmøZø.ùúÃù]ùcùŽù)úú‚úÑùnùöù ûrüãýÿÍÿÌÞ«ØBšÞ ìE k Ê œ ¯*07ÿóýÏý v…æjý  rºRüøSõ]ó ó‰ôÁöóøþù¯ùõø•÷öºôõÝö…ûÇFŠý ï  { a£¥áÿ¯þºüKúø÷/÷^÷õöböö_÷®øú£úyú&úûÐüßþÕKÏb-©°˜OvŠÀ[ ¹„ ó · Üÿ;6vý?ü±ýº£ [¥•¥\-L®a ÝHþEù`õkòEñ@òôâöú÷ú÷ßöõºó ó·ó¸õ0úÿ—^ £ ®  ˆ å~sÿêýü‹úBùºø&ø%÷Sö ö©öû÷Hùú+úíùÔú¦ü.ÿTÑø/Í¿oÏ+HrŠd ” ê Ð ­ i MÔyýþ!ý˜ý†ÿ«ÐEÛhÁ$Žc  Œ ¬ .1ÿýêø—ôÙñÚðÙñSôeöúötöŒônòªðáïuðÎòx÷åüºŒ¨ ò b ×Jvùÿzÿ|þ—ý”üZûpúÉø‰öùô!ôgôçõø¡ùƒú«ûYývÿÒãÔ3X .B”è0cî‚  § g È ¢ ÑsŠþ|ý+þðÿ¢Zð…÷8í  ‹ @6 { ûSþùÕôÏòRòSóõsöpöþô ó_ñÍï7ïºï×ñ)öbûW_÷¦BÂŽéÿdþsýüæûsûðúŒúµùá÷=ö2õ¾ô®õ¾÷¸ù³úûýüÖþ^_d[Aï¬õû[ßoì¢Z ‰ / ª r ×Ú•bÈþƒþ—ÿL錯mðÞ”4  4›Ä* €Þ†ý2ù§öŽõcö—÷üø:ùÿ÷¸õÀóòhñ†ñ¸òÇõúÆýC¯Ó_5M‘aþ¯ýqýBýýïýåýZý¬ûÜøèõró òMò-ôïö ù üøþC£ïf:À jÚ üª|—ÿÓÿ}¥Ãi » | > ‰‹ž¥²þþ›þŒÿe†öÿ3ïµÑ < ôn ‹ ¤Xÿ4ûrøš÷í÷¦ø2ùrøyö ô òÑð˜ðFñó@÷ßû-ÿùáJâ ÿ|ýüûÿú˜û`üNýÙübû;ùìöõeôSõÝö©øûTþ!ÿM ½ # O ñ à %­°–U}iE),8ý˜öÿpÿuÿ¾ÿm9Çÿ#B­À! º o Ÿg¹ ýhúÙøØø`ùú#ú²øÅõèò¨ðFïÑîçîÁð7ôúøúýO4¤ßÆêž¾ÿ¿ýðüEýþÉþÔþ~ýeûÐø%öôMóô’õÏ÷¯ú`þ³Àž  î 4œ  % ½ß©‡p#iSCFkÜÀ•`¿X²ž›ÿ˜þÜÓ•F  ‹ Ç icÈÿÔûÆùùù@ú¼ú]úŒøýôŒñùîŽí íwí·îòð|ôŒøSü ÿw«3ɃMÀþsý5ý¥ýÄþVÿ þHý¡û)ù¤öAõÊôÖôôõø@û˜ÿ³À$ w &  ó É !ç¢ä‰7 ê > ¾  T Þµ„!MÿjþHÿ@r÷Å‘) e ´  ® µ >ôÿ$üÑùrùWú¨û¹üÝüZû€ø^õbòðAîºíÕí”ï:òKõt÷£ù4ü­þc™l+WÿTþþaþþþ£ÿ‚ÿ™þ‡ý­ûnùB÷°õkôôõo÷-ûÍÿÿo¢ d T8·Ö . íè rj= ” L ÅÕê d÷íÿx"µÿ£ÿÊɼv 7 G · ¥ ù 3ªÿÍüüèü¥þÝÿ&KþAûGøÁõŽó–ñ‘ð4ð$ñÞò-õöM÷^øÃùEûèûTüÔübü·ûpûÖûƒüáýOþ€þvþaý•ûéù_øÖö›õFõ1öbøÇûlÿž²âä žê²vû ö ›³% · ­ M ÕbF”»ÿÆÿ¢ÿÿþký‹þ¹&F‡ O  Z = H CIýýü¤û¸üDþÙþÇý¨ûrùÂ÷èö-öïõßõ‡öä÷Šù:ú)úú’úû'ûøú¦ú©ùø ø‘øŸùÅúSûµûLüaü®ûtúùt÷ö|õúõ…÷0ú)ýôÿ·Où Ä m a þ ² À ¶ Ž   { ž }˜súÏ¢Rß-ÿ8líáE { 5 ⃒ÿßýtý–ýlþ„ÿâÿ@þ¦ûù÷÷õ>õ%õeõªöáø ûäûüü¢üÏüsü@üÃûnúJùõø7ùôùžú úýúÂû/üîû6ûú­ø±÷0÷š÷ù5û?ý&ÿx qš¸ ø Ø ‚†‡ƒã $  & u Y ²O'ŠPP½·lT#¿ÿþIüÎÑ^ « x ¢.Ðý,üëû`ü‚ýßþ?ÿþ3üúRøªööõÍõæõ²ö˜øÝù‰úGûiü6ý&ý*ý=ýnüûúùeùHùêùSúbú­úRûäû‰üÍüUü“ûûµú(û¶ümþ ¿®x='Ètýc |Tè ñ 9  Ì G •'åÿ‡ã©óÿâèÜ‘I¸ Ä Ežÿðûˆùõøù8úsû¦üXü»úù¹÷êöàöË÷³øÞùüJþÜþ\þþ$þ«ýêüiüPû‡ùXøøxø4ùÃùÓù úÓúÕûÉüwýˆýêüZüüüíüQþ°ÿzíxÓÏ € : Ö õÔK-kL>ç~{°Ë'T?Ëä9W+‰)q´4 êÎUCãüˆù®÷}÷Mø}ùúüùhøRöuôióÒò1ó]ô!ö¬ø|üJÿ­IkäAÖÿnýÏú?ù…øø øÞ÷øŸøãùïúåûÕüPýrý¬ýþíþ]Ô:. ( a ² À a   L¡|õX¯ís¡KÂþëüWü9ýüýþAþ!ÿ^r°G£  s ]ëë@ýxù÷öYöòö[÷;÷âõNô¤ò›ñúðIñúñóŒô0÷÷ùü½ýÛÿ¯îÊ`þü¼úúØùGùõøùÌúü8ýáýíýþ§þ³ÿÄ3•š  ó ïÇ[4Í a T•›¢Ù f " s Q°ÅXÿ6ýDüEügü˜ûúú3û/ýlBÄm ¿ v LZ#þ‡ù%ösôôô+õSõjô×òÙðuï–î`î€îIï±ð´ó¹öÆøpúü~ý”þ{ÿIÿãýáûoúÔùú›úgúDú°úÕûæüÃý]þ:þþý}þ¯ÿ¢ý&‹  kÀEÞ1Z1̤& ? H a  R ‘ b ¶¢Ìåÿàý0ýlýwýsýûü–ý‰ÿ$}Ò`9çÿûã÷ëõ®ôíôõ!õô>ò«ïÝì¸êøéêfê“ëÓíñYôxöè÷½ùiûÄüÑýÏýIüyúù²÷Åö öFõíô’õ<÷ùïú¦üaýþôþkƒÆš8¿ ³ ’~k?½C¡'y1ƒ  ”ÂVÿÿ•þ¾ýfýÚý ÿ*{¯ïä å å)ÿÔü ø”õôÛóôôó/ñDîZëNénègççÌç?êÝíñ\ó‰õ¶÷ ùŽû^ýuýü¤úòùíøÑ÷Nö„ôVó?óôbõ÷ÙøúYûëüAÿÖ'þ® I X×C/~ã«òèа÷Œ o ®ÿúþ5þëý©ýþ÷þhöŒÒ ° m À ̾Öü2ù«öKõåô¶ôŸórñ§î9ëjè)çšæñå>æáç ëïäñ©ólõ÷©øgúpû»úlù.ùzù1ùŠøi÷ö2õõ?õÿõš÷nù³úÄûýÿôŽûï2 Àˆº|δÜû  \.–üs= —¢1m˜ÿÈþÄþºÿ‰l-„Ç/Mäùþ®û0ù†÷l÷D÷B÷²õÝò¹îêFæÔä~ã›âMã:å±èŽì!ïHñåóPöxø3ú°úÌù`ùñù#úYùø°öAõ‡ôeôyôYõÍöø;ùžú«ü^ÿÆþôÊ”  SC<TÄ‚¢ÏΜVá$^xQv ÔVaòŽg¢LH Øù÷ÓLJ8vý®úø±÷E÷‘÷Yö'ôêð[ìÖç4åQãTárà(áŸãëçhëñí>ð¯òéôC÷îøÞøkøù0úeú'ùC÷*õ•óçòŠòåò<ôêõW÷ºøàúéý_v w ¼+¾­_ÔÜt >‰tvùv¿rß Hµ»ÂTxbâu‘ ê U  ˜A ÿûúü÷göö×ö,÷_ö}ôÁðòëè˜æ#äÿáXá?âDåÃèêê_ì0îGðtòGôõ‡ô>õb÷üø ù1ø9÷MöîõÈõ õÒõzö÷È÷èø÷úhý†ÿ`Z8 2 éë7žN\E+,§'è” ²?9 ­ © êŸEfë‹UA ° € Ž , Mó ÿ<ü:úzù­ùCú\ùd÷õó³î€élæóãdá àà@ã_çXêìËíìïàñ‘óCô“ófóõô\÷9øŽ÷Ëöóõ?õÏôuôžôuõ—öÛ÷TùµûÉþÂ)›B y ŠîW.ÎKêß/q2d>œ"¹ý-® “ Ž×³@¨FYøúˆ > é V g  Ðs>ýæúÕù¶ù.úîùløÕõñpì0éÚæíãBá©àôáVå±èÁê{ìTî;ðSòðóãóQóüóZöŒ÷÷âõîôYôôàó ô½ôRöøgù#û*þVJöŽ Â ¼ò8ž#0qXKÏËq*ÀE<)lÉ ÐÕr\ *Oa1›ÅÜÿ Æ Ñ Ú2ÿ¬üû¦ú©ú.û4úFøìôÕïMëÓèZæ:ãîázâÒäLè¤êúëœíÈïÐñŠóÿóóWóõñö ÷öõLô¶ó¤óçó–ôö\÷lø“ùû`þ…˜ZÀ õ}_`—oæ Úå½}¹Ð…Í«R#x ˆ nÀ xZ'ì×0ƒ¤Öý6A jý®ú$ùöøùãùøùaøÝõÀñEí”êïè^æ/äŸãÍäÄç–ê%ì‘íîîÌð†òÒóôíóÂôÜöÌ÷÷¯õÞô‰ôgôVôvô?õÖöOøxùèú‘ýÖú¹P … méÅWhTm&S™/P½Ãh3• íÍâT³Æ(_h¾ls%Cýú»÷©öžö÷øq÷òõKóçî:ë}édçRäûâyã¯åûèëµìîÚðåò»ôJõ ôkôöÕ÷øåöÊõõÚôŽôôFô/õöÉ÷;ùñûªÿBŽ : O1”¶ƒMU¾d+ãÌ%*ØsÝ{ ' :‰z+764A‡ÙôSp~ÿWû*ø#ö:õÿôÀõ¢õ"ôÏñîÌé¨çÿåKã/ááÐâæ,é;ëíHï›ñÄóôôŸô7ôIõ„÷¤ø øÊö.ö"ö?ö,ö6öœöŽ÷?ø×ø)úÔüûÿv ! r§7 —h•Fõß"Âq |Öm(E  °ß˜×$;)¥¥òåkÝüùUö;õõrõ—õ}ô•òšï[ë5è8æÐãÓà‘ßeà‘â›åVçé¼êŽízï…ñ°ñkñ÷ñhô€ö%÷Xö ööyöÐö÷˜÷¡ø›ù¥ú—û•ý‡{O ºÂ!4)ôÛVލi¹¸äÔòNf# } pÏ£¬a¤’¼‚¶¾£@.ÿåúÁ÷´õmõ¸õÍö—ö®ôòßíréÀæ©ä‚á:ß#ß–àÀãzæ‘èhêÂì­î]ð ñ¼ððòôùõ^õWôÒó´óóó’óVôìõÑ÷où¡ûûþ¨ÀT §u£ø*Â)xJ©Nb«xŸkj)Ùi)9 Þ ðáRSZ%;µ³ÖýÛùM÷Ðö£öZ÷4÷sõÞòvïë;èDæã‘àÄßÐàâãçñè<êìîGð­ñÊñÿðkñ|óvõ6õûó óÄòÒòáò¸òEó'ôOõVö¨÷fúþÓeYì gS7z@Ä ÚÃá ÔîÃ"ë ÆK<8r  y /Îr)v’XY›ß ÿ&ûù÷vöøõQö÷ëõ#ôñšíoêÕèÂæyã>áíàâåçëèâêíˆïáñ•ò ò(òôö£öfõqôIô­ôÏô¸ôÀôƒõeö„÷\øáùhüGÿzVµ Ï ?Ïtá(FÐææˆ Ë È íÒ]n…ࢠÿ O £ ÑÜŸþû–øŽ÷÷÷ ÷Yõóêï>ìê,èåSâéáãæQè¯é‡êðëví8ïcð‘ð‰ðòóôÑö–öÃõ#õIõÚõ2ö“ö÷±ø‰ùCú8û"ý¼ÿŒ0ÒN ÊÑáfÿEœ‡áîJ±Æâg£¼á¯ pG°Ï„ÛØ½ ǵ þ Ž U”°ýÝúnùÝøMù¬ù6øö²ò…îÃëêƒçä-ãeãJå¨çÿèeêòëøíÜï.ñ$ñRðáðÛòõˆõô)ônô õ=õ/õ-õ¿õ•ö¹÷ ùŽûÐþ_ƒ.f ÎŽ³? Þ_kBä?î{4šŠ ùÂjº Þ¿U¿éÿ0tO/PàÈ5Â/öþzü×úLúêù°ùøöóåïíìëÁé'çŸåÿåÜçüêÇììíïzðòBó“óØò­òNôŒö:÷ öõô*ôüóôáóôñô2öÄ÷ùªú5ý(ôMì Ú `,.)ÍÖ÷qoe~»•ä:Èõ  6 ç7°×•8¤qE{Ye 0 êüú)øu÷P÷Ê÷a÷êõô%ñèí@ìþê—è@æÇåÊæMéëçìJîëïæñ¼óõõôô(ö7øˆù ù ø†÷¬÷Ù÷ú÷ø‡ø{ùBú¦ú;ûíü*ÿ²ãïÓ½ K «lýJ›þŸ)ç´W\CËàÓ7W ž @L0c¤$|,±ï¢`®æ^ ýú‚÷•öNö[öPö¿ôròwï»ëWézèçåªäÆå/èÐê%ì^í-ï)ñ6óóômõ õƒõ¥÷Éù@úzùÐø”øÃø7ùùøùŒúûØû±ü^þý®°\ Yô wU)ë:e(*Í“ØÔ=!qš Ï H æ+RÎ Âï‡kâ…RšþGûkøØöqö‚öÿööôwñóíúê%éäæƒãá‰àâZåè7ê¯ìGïíñFôKõ õõö¯øZùoøœ÷p÷­÷øCø·øŽùÉú0ü†ýUÿß›&# L Õ ?_ÀBkÏA1¬XãÅçEgõU¸â> 6 m^î>ŸîT'ànkÿ6üTùQ÷Àö‰öåöCöpô;òïÞëwêüè†æNä¿ã’äÑæè‚é†êÿëâí ð ñò[òôËö˜ø>øt÷àöüö˜÷ô÷qø?ù úûüTýŒÿ4[Ð ã ¢áM’Êã·ªM÷öÚ?õùÓ & ÷~fÂÙØœ\Õ+I3+ÖÈþßûù“÷iöÒõÔôÕòŸðî=ëóé{éÁççåZåNækèÈêÿëÊìÙíjïoñÈòèòŽò/óõ‚ö”öþõÇõöÍöd÷â÷»ø ú'ûWüªýÛÿbÎÝ W ž¨EW‚˜²˜á k‰' Œa6z ö ×£R¤ ÄࢱÐPþßuê içýqûíùùù‘ø±öÜó˜ð½ìê™è³æ^äãã÷åÑè²êCì îãïÝñó¤óGóŒó?õ÷…÷èöKöÂõÑõëõéõhöz÷­øEúü`þD%Ü ‹ ÷ *Þ?¿Oƒº óJ¹«8Êè7U˜ *  Àì3Ísïeúì­øÿ)ýeû ú«úçúHûÞù÷Lô?ð´ìÁêŒèæƒäoä1æ éëHì°íaïdñGóžó‚ó´óCõX÷vøø8÷töööÈõìõ­öª÷Íø"ú2üÿéó±Š  ‡Ú×Ù¦52¼-±´æ Å ƒ9NWœÏƾZNJ‰SÿÌüåú·ùuù ù úBùz÷õÎñ¥î.íìæéègç3èWêùë6íMî¥ïñópô9ô+ô õÐö®÷7÷}öåõ¹õ9öŒö¿ö©÷”ø±ùûµü2ÿ÷z¥C û ë ôÉÒPQ=6AØ¡. k&)ݨ  íF -x±m™ÀízI3¢Ò÷þíüâú9ùÅøSø{øî÷Yöbô¾ñnï÷í`ì‚éqç¸æÁç1ê‚ìÞí7ï¾ð ó}õ°öêö(÷Ù÷'ùêùŒùëøÊ÷þöøöõö¶ö}÷wøÂù¯ûÞý9‹¢•Ò oО6r†#¹ˆVmñ\Ÿ ;Sä  °ïÂ7Þëï%8%’~DzUÿýúû[ú ùø¡÷{÷Û÷™÷àö¢õQóÕð·îHìzéöæ å"æuè¼ê_ìÚíÐïgò$õ ÷m÷F÷¬÷éøÂùèùùØøÁø1ù4ùÜø>ùõùŒû7ýÂþŽNã¿F › ¢üý ‹së’$|ð0nÑ• * l|Ð:Ìèkða#ÑþêýýùûúZùcøI÷ öõô–óÕñùïƒîxìFê’è>ç˜æSç$éâêkì1î#ð“òõô²ö;÷W÷r÷Ê÷ø2øø"øìøÀùú*ú_úHûøüíþNˆI? 7 Ð (I~Źð|ÏwñóãglO©“  ªÃ‰hë{šðS rÚÿyþ>ý¢üØûÎúúSù5ø˜÷¤öfõUô÷òjðOí’êèºå ä?ãßã›åèvêQí*ð½òxôbõ¬õåõaö°öåö4÷ø#ùÊùÓùpù>ù ùðú)ý‘ÿ»Ñ@à— #Z`B„Ô»nƒJ‰ñ5g®« ë ¤  † \ > rþAu…&á—þýâû„úÁùŒùùÃø^ø ÷†ôÍñáîìôè>æ‚ää}ädåšæUèŽêí*ï’ðñ]ò¼òåòóòMóô=õ—öJ÷º÷4ø+ù½úvüPþ`ãS¸ ç ° *eÎÀ_fò*¾Bõ¯?: hÒ[ñ\ÃG Ž 0 ®-jÃûÿ…þmü¾ú ù7ø:ø›øšù•úYú¾øö ôæð“ídêêç­æ‚æ²æ{çªè8ê]ë ìçë–ëÛëhìí®í’î§ïµð¯ñ‹òœóßôVöñ÷lù¤ú—ûýæþË Qu| ; R ? ôo-†¢«“¾bEâ°9"û/½ÀÞÌ©ù rƒˆ÷jìÿ:þ9üVú9ù¬øþøFùŒøÕöõ,óÌðáíëéžèøè³éóêqìøí ïYï î*ì¬êáé´érêÖë›íŠï;ñ-òò•ò&óô4õMöh÷#ùûüüæþÐÒÒj)ð} 6 ÷›&Ùî4|íÚ’äfLÑD\›«|; b s ÂñËï]ÿòýcýýNýÌüxúš÷ßô[òiïBì†éÂçWçˆçwè×éÉëoí îîbí8ì‚ëë¹êëìwí/ïIðøðmñCòÊóÙô‚õFö±÷où„û¡ýBÿñ{ÁN]-Í U ›(Ì–ÌôÍÖÙŒ0!Ýùù5‚Õ»@¥ $ ŠÛÅV¼¨3Tƒü]øÅô!ñ<íµé=çNæ—æÁç­éEìöîñûñøð®î’ìñê­é$éFéÝéèê2ì}íÕîÜïñ„ò¼óúôköNø.úãû„ýmÿ_'6pú{ ¸ 3 Gó™#/â$íø œ$  bÆmEŽ‹«Ì Î ñ ÿM]ÿ…b6¾ÿÝú…öÝñíÓè£åäÐãää,çnê®í6ð&ñ.ð|îíÐëËêfêpêÁêkëìöìòíÌî9ð~ñ˜ò¨ó õÑö}ø!úôûþÕà~ÙQ~ kì2Ú0 NÅ€®ã¶ý ä•;ø _ÐùïP Œ ž Õu¥/h‘âCCü;ø2ôÆï}ëãçÏåìäääæbèÝêèì[îñíkìøêðé>éãèØèüèJé…éÅé‘ê¨ëí«îÅï¬ð„ñóªô5öØ÷ úsü½þhïŒã. a *rÛÕÈ“íMËWµ !!N!H S«múšU6Ç ‘ ~ .Þ? V  4@ÿ£úÒõ¥ðÂëÔçå@ä;ä’åúçgê‹ìíìÐêàéé‡è èÎçÝçè0èÀèŒéLê5ëÅë ì§ì=îð¾ñ½ó,öâø>û3ýàý÷ýœþ‚2¢Úä v–õ¾zù¢Ç!" #*#"®ÕÈêÆJ’Ò8 ƒ Ô - ã Y Ogÿ,û{ö­ñaí1ê5è?çÎç·éÿë6îfï‰îÂì"ëšé?è%çBæÛåæyæXçèÍéˆëýì¿íî:îÄîïºï&ñˆó§õ™÷ÈøùÚù£ûvþfŒoÎ >  Ì \ ¿ ¯ ïÝÞ V"™#_#H"ó’ùÝ'”Œ]$BQTæv;» Æ¥˜þìù"õ›ðÜì}ê é²èê*ìaî ð´ïîFìäêÏéénèßççVçbç¼çƒèÕé‡ëÁì¢í)îQï ðñHòôÇõL÷øøšøqùŠû=þ˯۴¸ ã  …  - B ­ûΙ_º÷]åoU¸¨S;a)ý/ê|Ý1èˆ + ¡…ÿ'úõñiîƒì™ë_ìæíœï<ññ8ï!í5ëÐé„èzçˆæ¾å/åÖäðä`墿wèê}ëÛìçîÞð2ò2ó¢ôXö°÷Ÿø‚øCøîøÜúªýËÿ2Le „[ðòo ¼q9Ë@Å—Ú>á>‘ô¢+±.\+Qÿ Åóþ úÔõ?óKñNðÛð‡ò0ôçõÊõŠóçð¹îáì4ëÈé€è{ç¶æðå¾åßåXæIç¯çŸç±çlèµéëÄìSï˜òìõÁø,ú°ú—ûøü¯þ© Kìd1îcZÌo ˆ$8 ×^?â=Rüž1xÈMv«áP%i€Ò Îp‹ÿ©úûõ´ò_ð3ï©ï¸ñGô ÷›øû÷-ö3ôcò§ðïîií ìåêýé:é©èrèéè6é=éZé¡éŠêJëìŠíËï`òÛô˜öf÷‡øú\ü™þÅÿÜR›ê3WFé g;0v•õÑv†lu,â­õlÉ~Ä è Oó)  ®½]þ"úûõðòôðáï)ðøñLôáö¦ø,øöäóùñ:ð’îgíìÇëNëë ë'ë¸ë^ì6ì£ë'ëqë÷ëRìñìŒîˆðyò$ôÎôzõÌöAùdü­þ”W¦oýâÃÏ“ :'É—ºŒT)ïS–ü báÏvóËóW~{ ÔvÝÿ¾úõõ,òœïàí¬íAïiñôDö£ö9õ¢óò´ðzïdîníHì?ëpêºédéŽé*êHê8ê*êÀê ëEì,íðî(ñnó›õŸö ÷Í÷ ùûnü2ýÔþ@A…ñq3oÔ2 ôëÁØÄ¨'¥‘hDù¬+–èbn€× AÏÿqúéõöòÖðð-ñ„óöžøRùˆ÷üôÿòöðïIíì ëJê½éFéúèæèõè1é7éuéê7ëì„ì˜í²ï­ñAóMôôõö'øhú:û•ü4ÿ ɇÀ¯  ³™þ쇎¾¡Ò …Ú#"Râ*o†Ád-( ý©Oþ¬ù>öÊóiò½òõ¡÷ˆúžüªüû%ù÷AõÖò·ðîéì¢ëéê ê­êðêüêqêÒé1éMé…é¯éê¦ìï)ñ óÜó‡ô~õP÷-ùAú*û£ý³ÿð ôàÅz ‡ª—ÆéðÝöß m–óz ³ ú †M]DñP û¹Rþýù ÷Nõoô©ôlöžøÿúóü#ýÊûIú"ùøˆöõÑó„ò<ñ)ð(ïYîîî»íípìPìpìhì„ì{í²îýïDñ¶ñ³ñüñ'ó0õšö–÷6úÔühþi¨¥lU:WÄ ¦/í×É㬠 ½¢»‡£—  Y Á ãk¦ý 6ôÿýâøêôQòòð)ñªó÷ºúþEÿþ;üqúù‰÷$öúô´ó¬òò¾ñÀñêñò©ò;òàñåñ.òòÌñZòóÇô×õö¯õ®õoö8øNùoù¯ú+ü5ýðýÉýÇýFþõýÖý×ÿ„V ´j/VêÀø+[}dIµC¶r  p  * .?Þ˜ — “§sý ù‡õ óPñªðÙñ)ô%÷üù$ûBúùøøƒ÷¶ö•õ½ôúóYóèò…ò2òèñcòºòÀòšòêò’óªóqóô]õyö™÷.ø øLødùû&üü/ýæþÂÿ£€U|tÐÿB $ •Ž­:Y—V‚R¥V†ê×É“  ?Ã8u¸ 7Ç¡ÿPû ÷sóûðïï|ðó,öJù¢úú¸øº÷ ÷.öüô%ô1ó/òRñ½ðmð–ðñQò"ò/ò˜òó-ô]ô=õßö>ø©ù¥ú«ú©úlûý/þ^þŸÿ±·˜ÄÙµF«aĸiTâZ›ñp#s“cià ( Ä @ m ݯ%Vt é±íýÂø)ôæð˜îwíGîvð_ó™ö[øHøçö¡õ¦ôµóqòÂñ¬ñ„ñ‡ñÚñäñõñAò:òKñlð4ðÚð#ñÿð¸ñdóôôÄöVø0ùú\û}ý ÿUÿ†e5»êÙÖ— XϨ ˤß|r\èºò¡^ Ç ð . b ìï}ã- v¾Üý¤øôµð€îhíî=ðëòÍõV÷L÷vöõåô[ô+ó0ò}ñþð‹ðPðCðvð#ñÐñöñéñòmò6ò³ñ)òžó'õÂöøbøù‘úüÏýÏý¨þI÷­Õýö­Ðšì Ž7 3™Ye#é®ÚF `– 6 Ø C i5ÿ  1ö ýƒøüô5ò—ðÍðTòXô»öW÷`öœôþòåñäð±ïPï{ïôï ðJðTðð&ñ¹ñ¿ñ¾ñò]òhò!ò¼òYô¤õîöTø ù’ù½úsüˆý¼ý¿þ´¦¥”ÅJ¥¨ÿYˆè_ h1[D„éÚê3à•ô r · t ³à¹ BŠW] ¼Äyþêùuöÿóëò‘ó­õUø'û ü“ü.û`ùÝ÷PöMôÍò¤ñàðWð5ððð¡ðTñjñcñ–ñ7òmòPò#óèôšöCø¸ù,úhúMû ý þtþ'@=¥-Ö¨C( 1î‘y,›5¼ßÏ 6 C ò¯ü$pM ç Ü ³ ?óû—÷¥ó!ñßïðÉñ£ô øû¤üŒüsû&úSù—øj÷köƒõÜô&ôôôåóôôƒóôòùòZóIó<óëówõåö‰ø úÃúHû¢üXþÕþ<ÿœbm¯EcU¬Ï šw—ˆ^ñÂÕ8( ~ ùuû¿á] ™ Á 6UùýTù˜ô†ðzíuëÚêØë%î²ñüôÎö÷ºöIöö¡õõôHôô…ôïôFõõ„õ¢õUõÏôvô¤ôæôëô[õ·ö«ø•ú¨üþÞþiÿá/5*lÕ¤OþÎÖòô iëZ°”„hñªœµÄ b u çB« ‚ T Ö 0 ±B`þçùZõ˜ñvî6ìDë¹ëí ï{ðÆðNððSð»ð›ð;ðâïð`ðqðÄð2ñ òÜòëòƒò:ò:ò7òkòäòô§õ‡÷¡ù‘û3ýAÿ¼©®Ÿx´2¬< O€¯á•¹1˜ÊÜú!—ú\ Í Ú s  (ÒØß § þ ùNôÕðSîí[íåîgñ¥ó”ô(ô óÎñÆðÄïäîõí\í˜í¹íÐíîqî:ïÊïÐï­ïÞïAðNð7ðQðÿð!òÍó=õ9öe÷Äùmüþÿÿ8ˆi‡¤ú6¢Ñ¥% tÎÁŠõ®dµaòçÁ£øº i • M ý‚Þé§ å GJWû$÷ƒóøðÔï\ð1ò…ô4ö¥öùõÉôó†òYñ=ðøî¢îîŽîïþï0ñ&òSòsñUð„ï’îÕí í1îŸïØñô¡õ™öøúøúgûˆüý[ýgþÿJÿgÿÿTÿö}§ yt%8€L¹d ‰”Lìð ™ ÏÍŠºVŠ L‹îþþúþ÷|õÝó|óô¬õA÷1ø×÷‰÷,÷óöeö¬õžô·óaóÃò.ò ò‚òlóôþóMóµòAòÄñQñ%ñCñ,ò÷ó{õö„÷mù»ú5ûâûœüÔü,ý¦ý8ýGü.ûOúÈú&ýHXü ¡FÔÖç• aô®ªü u A I ¤ ½ 'AYí°[ øPÍý<ú:÷ õýóÑóÎôNö›÷½÷%÷ÌöªöoöøõŠõ!õ9õ>õ4õ‹õköÕ÷óø"ùbø@÷öõôDôô…ôLõ%÷éøçù¡úüŽý‘ýÐýƒþˆþ®þéþ’þ—ý ü;ûöú*üIÿÔX[ ¢ *xøIRB³g;!< MQè'î¹ ²¯…ÝF * Rù“ýúW÷,õäólóôÅõJ÷Ú÷c÷àö¬ö¢ö6öŽõŽôÖó_óúòóðó õœ÷þø“ù€ù2ùoø|÷óö÷Y÷¢ømúÆûÕü£þåÄgH¥ ©Gøƒ/ÿþý0þ(u ÇÜÚσqå6 Ö oϤ îu Ò ¤!¾ûXøöøó‚òëñAòKó¤ôƒõ\õøô¸ôäôÀôHô¦ó]ó>óÒò¦òó9ôÊõ÷÷ƒ÷…÷÷‘ööÄõïõ×ödøßù;û:ýøÿëOÉÌm6‰Â\¸±‘Y r ëH\-vÏð`Ä ìÝ ŸŠÓEº= Æ H= ” 'lÿUû¸÷OõLóêñ0ñ-ñìñúò‡óAóµò¡òósóóVóýòÑòCò¨ñiñþñYóô3õUõ@õÞôBô§ó}óíóõîö„ø±ùû;ýéþ˜ÿ£=1·[êÐß&öÒ@ 0 Ô; «/+yØÎ± ù‹Œº9! üçÉü –Ñðþ|úc÷ÏôÐòµñnñØñ½ò„óƒóóÂòúò[óYó!óÝò–òÔññsð®ðÿñ™ó¹ôYõ³õªõ0õ–ôôØó5ô–õ,÷cøÕùüþÿ_Ú™.!~ÿuþ–ýŽýYþ Wì Š“·Èþäkq}˜kl 1Õ•ÃÈ É‚% Zhüäø¹öõ†ô’ô2õúõ~öCöqõ»ô»ôõMõ5õÃô¢ôô.ófò<òùò(ô[õ ö™öÈö^ö°õ õ|ôfôpõäöÿ÷ù%û<ý|þçÿg.nØ3ÿìýýçü~þ3+3 4 ï *üQðÄ9Ø”N äS } XƒuÄ H ¬w´ûZøö{ôôFôþôíõØöàöðõ õBõÉõÿõûõíõfö§ö†ö öö÷‰ø˜ù8úpú-ú~ùø=÷/ö™õKö¨÷ùÓúSý^ÿ§òd[#÷N‘ÿpÿöþ©”ç– ¸ ŽÃqÍ1'ŠFygÜ ÉžÕéEb®  F Ó 7 Nþaùõ<óò·ñáñ]ò-óô;ô©óâò»òfóô­ô)õ4ö÷l÷a÷T÷ ø`ù úCú„úoúàùsùôø|ø~ø®ù`ûÑüqþÿÓ´ Èb´CV ÿÑÿ,—íl çÌ›€3‹ÿጠ> ‰ýÂs(% ãÐ$v t¢øý øLóð2îˆíŸílîmïVðªð:ð¡ïîïÓð¬ñWòäòØócôqôsô{ôKõºö°÷ø‰øùOùiùÑùVú¹ú¼ûý0þRÿ‹šl:é׉±¾š“ Þýr #y_ô ‰çaX,Q.f– €þ¾ë;µ 6 Ö‡» ä ã0üâ÷µôBòÄðÙïÀïÎïûïŠïxîí£íaîtïð4ñFòâòó#ó]óFô_õúõöYöÄöëöýö.÷5÷Q÷øCú²ûpý,ÊF!\‰á½›Îíµ.Øóú Ž ÅÀÐÓ@ê«îPˆ? Ò éîëf = %² £ žÞJûÈ÷ õ5óâñàðžðŠð†ðÕïwî=íóì{íî¿îŽïôðìñ—òFó<ôäõ÷SøTø"øÆ÷÷™ö‘öözöŠ÷ùxú[ü;ÿŽÚ, ²f• ‡e3Y¤ °hC*­pùÈK‡6ãS Ó| ¢S sœ Ûðþÿ÷ú?÷Øôóyñ¤ðóïÒïJðýïïCî7îï?ï5ïuï7ð¥ðfð:ð ñóQõŸöäö÷3÷Âöböö»õpöoø”úVü[þüézÙX߬’  ž3ö+ý Ÿ 뛡4GÂ5‘r‚™ 8 t''ù h ŽFI –1úþ4ú¥ö–ô>óLò6òÖñ±ñ…ñ¥ðNïîÐífî ï¹ï»ðÝñnòXòKòYó4õíöª÷¼÷ë÷P÷höSõIôÃóXô'ö]ø”ú‡ý+¡aG3ò0ýÉÃQkO~ à ÔsÄâíY~40B• ÝžLs å ¾ ôPÛþûwøk÷Íö×õBôcòœð ïíÒêé´èêìãíÐï£ñ€ó«ôõvöY÷]ø…ùú»ù ùAøçöwõ¸ôrô¡ôöþøÌü4bç‘+92÷»¼´†â ÅÚ÷s οÏÀu2DšÓá î/ } jLe ÷`â<ÿMý›ûkú4ùØ÷ÆõóÅïûë’èæå›åžçêìîÃïÈñÃó¹ô¹ôOõöŽ÷¡øUùüøø÷Äõtô ôxõw÷åùˆý¢û¼À4| –dø/ Ò 07ë; ú ¶&\ËÎKü¼ Ö ¯  kEóà D §!Œíõ|¤·&ÿ©üøø>ô&ïïêJè,ç<çèñé¸ì¹ïcòïóôôó[ô¹ôSõöõMöïõ7õ`ôÀò´ñ+ò‚óaõø…ûÝþ^‘œÅTw©W 7MŠÐ=ÿÐÿãÐDö PLc¨]È+H°[j ² ,ŠvÓ9”ì5-8ûþ¹ùèô~ñ‚ïAî\íxíTî½ïÚñ½ó¤ô õ·õdö ÷Ï÷ øt÷¸öŒõÎó¥òwòyóòô¢ö_ùäûÄý¦ÿúm.ÛGL¯n9‚þ ýiýÆþ$ì$ Å  2 L  À “ñ²^Ua §Å$~HÝ+5B.}Žýìùçö©ôµòcñbñFòöóÙõéö÷÷W÷‚÷û÷òø{ù^ùÍøW÷^õ ôBôöõÕ÷Úú¶ý…ÿ¬l]=àm(1ÆZ†Òý ýÓýáÿßh‡¨”›@ ‡E†ÑÖ à H’i* %±öWsÝjŸ3&zŽýqùëöÁõœõ;õ¾ôöô¼õ÷øù÷œ÷¹÷@ø+øIø“øtøÒ÷P÷-öþôÄôçõ”÷4ù£ûßý,ÿ_çºSÂþµt$Ö.îÿ–ý¾ý¼ÿ7rå‰% ÉüK‰ úˆä .c¡6 ½õLÿÖýiþsq7e/Ïÿ<üQøŽõ ôšóoó(ô×õø9úDûû.úÉùRùjøøƒø­øSø€÷Àõ‚ôZô8ö8øú“üƒþ¡ÿ®,_§¦£î÷  O „þ<ÿ(Á]> ´ . ²Ì¾ð…ùc”7 ¹ ÿ # Cû ,m>à%™ýFùšõóó*óÈó>õ{÷4ú¿üBþ†þäýBýºû½ù†ø™÷rö²õÃô¢ó ó‡õ%ø!úãûþaÿÖÿ•kWŒ"à੺ÿ”ü£ûðü«ÿüá³ K š ‘g>8ký:  •ß V ùÄ,Št ŒÃ„\,èþ üªø$öÒô‰ô}ôæô“ö-ùEü…þgÿ5ÿÇþBþöüÜû-ûfúrùø_÷Höµö>ùÿûŒþÖfÍ €£âÝ=ôÖåkÿ4ü›ùÎùüÛþè% Å ï › ­6Æþ³ Êv ‘ î ¢ Œ ïã t5éþwd’…þžú÷ÒôÂóªóàóÞôËö°ù«üŒþSÿ×ÿ4Öÿ}þpýÁüÚûßúÏù5ø–÷ùüîþÂrˆ¥§º1L{wŸ•^ýNúù4úrüþþ§®±ÇÓ€ÒºÿU©?­ Ð w Ð <ØSÌÿ-ÿAV¾ªX0ãýúú„÷Åô_ó#ópóÝó\õÆ÷èú³ý`ÿ:¯äÔÿ6þ5ýWüûÓù¸øË÷ZøTûóþ­ÿo¡± ~fY à , B ðDô6‡þÎúÐùTûåý(ßlß© âÄþyý*ý™ýŒÿü3-  ° ´6ðþ!ÿªõ&z]þûm÷ßóœñ¿ðïðXñòâóÓöGúýÆþ’ÿ!úÿ±þýüßú°ù±øé÷æ÷€ù)ý×ÄŒ@Ï7  ÚS â%G-“×®ôÿŽý(þOf€û±= qð]Öÿ»þøýÜýuÿ’ÏÞ Ïn¬U¾ÿ}Àd ÿxühù¶õvò ðÙï›ï\ï*ðWòÔõ.ùsû©üýVþþÄü«û~úÞøX÷ ö8õ#ö9ùÐý!´ s • Ó z ¸ F û ‘ ¶®Œþßýÿ£h“Ÿq­Çebÿæýxýý$þî# ´ þ‰\Bÿþþ¢ÿVyhýOùæôeñïî¹íKî7ðoó>÷cú|ü!þkÿ¸ÿ.þükú÷øe÷½õiôþó]õ2ùBýÒ- ? Ï ­ ß » 5 ¬ " H ç Ne8þºþ¸KK ^ ³ O ;?*rþÌüõû@ý÷ÿ­¬m÷-K4þ#ýÄüÑýXÿ‚ÇþAü¿ø…ô¾ð|î’í…í!îšïòXõúøoû×ü¸ýþkýëû¼úÈù6ø„öÌô™óðóUö{úSþâíìØ,  ÿ Ê Ò Æ n í £Ý!U„‚P ø  Ô  ´x®„99º o4Sþ.üû+üçýiÿŒÿƒþ×û‹øtôð´ìÞêOê†ê“ë›íðdô˜÷œùÐú¤ûÎûû<úÐùÊø:÷fõ‘óÇòéóY÷HûoÿwlÌ' ß U _ ÿ  P å B ñ ø3 Ô‡°1e 1 ª è _ ”²ˆI©U± , ( á ‚$a›ÿÿ™ÿ± «ý%úöyñ¥íë¿é2éHéŸêíªðhôV÷9ùgú®úºùø£öÛôâòöð3ïuî;ï„ò;÷òûùh{ü æ z I  C _ 5 i ¤•Ü–%î 1úk q Ó™ÒF ¢ ”ä Ý n•èE'L*<ÄÞsþsúµõ$ñ%îhìhëMëíë²í›ðýó¼ö øúÒúnúùÈ÷Oö‰ôgòÆïãíTíï—òôöuûiÿÖ‘ñ§» … º ! ê è äˆÙÿ³ÆÈË Ä dɯ  ++pAè)  y œ“ ¶ sŒ¤€0v*÷ þuù¸ôñÅî¾í~í¼íÐîíðáóö'øwùXúôù†ø"÷ÖõôsòŒðïîcîð„ó–öŠú7þLzU­ë»ýnM4_“g³þÚýÎþòµš — * ž š—Õr”êp¯ Êzë _ ™=¿uY'¯ÜY!ëüHø|ôòñæðDñòÒô°÷zúMüýFþÍýKü“úùX÷9õÁòþïBîˆîZñõQùý!¦cPoç¼Öc-‹=ý»û0üIþûÛÛû  »Æ¨a™Àà¢$ ò*œ¦ aÌfßœÄGH YW`ýâøÃô'òÓð?ðOð>ñ)ó7ö…ù×û†ýøþpÿVþ´ü7ûÖù£÷=õèò1ñˆð˜òŽöëúÿDå¼åáÄå… |ŠÄ3öþ®ûÐúøûàý¿¬ð3 ¦qäìÐþ®ýZþÙx5 ¸”#ÅC²{âw 8 °Ñ*£üøaôAò0ñ0ñÏñ$óeõ;øZú˜û—ü?ýÉü¨ûÓúùù±øýöÑô óõñîòðõzù²ýxþH1t. A Í à L G 4 }bþ­üõühþ6LT® „ý]G ÿÌýUþœÞ~Z “PáºÿVÿ,¹ PžÚzÿüLø»õ%ôuóJóŒó$ôÑõjø¸úCü‡ý¥þŽþdýöûÓúFù5÷»ôkò¹ð²ñ†ôØ÷ü)ßo½0½B  - $ Ò µ R ØÿúýrþX$û% Æ D â Y~ÿ¶ý¼ý¤ÿàÀ„ Û @}ÒØ´ÿ«ÿˆ¢cÞ_}áýzú¦öqóCñðÙïðýð>ó¼ö<úèü½þ%sqÿ˜ýÁûµùÂ÷&õåòñ&òõaøuü&` Þés³ G œ s ^ ;†úÿþ)þžÿj”% } ® Û Ÿ Á~[«Þ}†¸ { »Fáwâä Ù(„SHþNúöiòðÐî²îJïðQòõ÷{ùþúRüêü†ü”ûúäøèöŽôLòòðEñ,ôÐ÷6üN7EnúRÕ É •   ~ í ¤:†þbüHüÂý=nT é o 1 Q dt-Œ«YD Y Í9ÌhîGr)ôßü´ø&õ\òÒðNð’ð†ñSóö¤øpú´û·üïüWüeû9ú¹øŽöôˆñ¡ïŽïWñÌô§øøûÿÍ«˜ | Ò È £  K#Dÿýüdü[ýqÿqä‰ P € â ˜˜bißÊ,‰ þ ’ ¼yΜj¾2:[ÉüýøÐõJóÀñùðñÝñVóÓõEøÞùû2ü¸ü·üuüøûÚú/ùçöGôò1òÎóïö0ûŽÿážf5#Õ‚çý>çw9Wþgü&ü4ý4ÿàiš ^ / jÀ·s6²Î©Å@ ೆœŒ)ñOÌgc5*þ×ùýõóƒñ¾ð$ñòºôŒ÷oúuüåýéþøþíýüû±ù¾÷aõóPñ<ñEóýöÇúîþß4ÒI¬ R Ä X / { M õšþ/üû¶ûAý­S™‡Ì  Œê•ÿŸÿ’}OIXöPØÿgº± ._ü=øµô'ò„ðÎï ð9ñóâõèøXûCýðþýÿ jÿÜþÈý¾ûÔøßõÙòõñÚòƒõù¼ý»S’2 ½ ^  ¦ Æ A Ú Œ†”þ ý^ýµþåŽ^ °  üºä¸œþþ²ÿ`…2ÖöÄ‘ÀjÔ¬'lÿ˜ûW÷)ó=ð†îíÚíï:ñ˜ô»÷Qúãû%ý«ýLýlüû•ú#ù_÷(õ"óóõøfûqþ'kÚWU ´ ö . î ´  Z²1ÿÑÿX°D Y ­ ‰ šæä˜[’‹:»+ ñ§ëÿWÿÁÿ—”xÔ¹ZÿùûÚ÷ôò)ðüîî­ïŠñôóööøxú—û¤ûáúµù¤øº÷höêô-ó—ññÎòJöcú¿þuÌ2G 6 ð H  j ä  Î Ý»íÿÃþÛþb‰¦Y À ô Ô † z {£®›þÜæôŠs±åŒ{À‹xªÎ˜ÿ›û£÷pôñZï®î*ï0ð\òŸõ ùeû³üúüiü˜û‡úù‚÷-ölôÊñUï¤î-ð¤òZöâú¬þí- ² Ç û ñ þ  G"ànÿƒþ^ÿ(uÚ5 ³ ê  ÜËM#¦%ÈÀiv3ä\ƒ¿•ný™íÿäûý÷gôÆñXðËïÙïÖð†óøö¯ù•ûpüüŒü5üõú_ùø¹öªôOòOññîòÊõHù*ýGÚ® ¸  ½y ‡²Çþçÿþ+þÿ Ÿ½lÂÔ% 𵀏Gócm|àá‡{ÓËpß ´ÐþYüù÷tõ>ô<óQóÛôd÷öùáû¹üÑüÂüCü¨ú¯øR÷döEõþó×òšòó„ôJö`ùýªJ. * ó G µ œ j ó…^5ÈÖßÿ|@+˜Šv]*Ï:ÿêþõÿ¬= ù{GˆªRÿZürù÷¥õ¦ôÕó=ôö^øÕúý‰þ]ÿÒÿÿ>ýùú¾ø]özôšóOóôóîô¥öÀù'ý•”M®n–ˆþ%¨wî‹.…þt1°|Ü6Ñô!2xÄ·ÿ„ý§üÕüý¿ý7ÿvÝ¡iO0Á6ïÿ ý‘úäøÏ÷øöÌö˜÷´ø ú±û7ýþíÿRBÿ¯ý¹ûùY÷éõõÿô§õ ö@ø‰úJý÷žw†€f~,•$r  1ж Þÿ«ÿ5€øS f#-ÿ£üèú úÇùnúôû‚þ³ ‘;xlsþü@úùhøñ÷Ø÷ðøÆúkü¨ý…þeÿxáIÿ‡ý¹ûÖù ùœøŠøUù€ú/üUþ?vÏXÛ̆µêŠ˜­hyù^œ(‡þ5ý‰ü„ýG|‡ z « *ö‰…ÿyýWûiú(ûýÇþÌÿGQj„Pÿâü¬úyù¡øª÷ùöQ÷:øù½ùúû¯üÓýÆý"ýñûºù÷mö®õ%öD÷Gù·ûÎþžŒ~z~è~t+‹  Ê à"'—!½/<‹þ&þ±ÿU³òêÛŸúÁ1ûþÍüüµüñý+ÿV29è&ƒþ‰üÇû§ûcû@û>û¼û,üÑû<û.ûÉû¬ügýý ü4ú÷dô:ó³òÇò ô;öéøÀû€þ„ï#g€ÇpK¹ÒW”ʬ§£4hÿ‘þÿÜ”l± üÝ$`4£ÿµýÓüüýêýšþ÷þŒÿÉÿªÿkQáÿªÿõþ'þÎýþ¼þ7ÿIÿŠþÔüôùe÷âõOõ+õ[õûõˆ÷0ù»ûíýaÿ’b9ÿôþÿ\À¸+rÉ‚ð°`Ô4ýÊFÿ$ýuûìúxü[ÿ3PKÒÎÏv£ãÿÿ“ÿ›ÿ 'Rÿ<þªý×ý?þ‘ÿ9MûœcÒ9„È¥ßÒÃýÿEýþùU÷ïõ»õ%ö¼öøüùQü9ÿî”EìÿPÿ!ÿ{,nõ|Og<Xz¸zþÃü~úî÷Õõ¢õ‡÷qúý÷7*ç9¤—ÿPþjþrÿ×&Aoþý&üáû€üÓýHÿ“Ïõ)êÇ@þv'ÿü[úYùùø:ùòùšûýeVä;üþmýªü÷ýýÿø ù2 Î Ç3â½Õ9ÿLýfúÚ÷uö ÷Qùµû7þ`ï?„V ª¥ÿÖýý˜ýÊþj1a¸þ=ýÿûDû—û‰ü¦ýÿë¾¹˜SÍi”¾s=0þú¦÷nöUö†÷ ùGüPÿ$a-k‘óþ#ü}üPÿ›· \ 𥵴$¬þ×û£øö<ôKô#ö«øUûbþuƒC¿Vó`mÿþÿý7ÿž¥uh‹þªüŒûrû¨û,ükü½ü»ýTÿ$¿ c¡bîÙcþUûùjø ùñúý•ÿ öe~MJÿƒýdþäÀò = ëŽÔ9_Rõü°ù¼öÚôˆô\ö§øTû!þ”ÿ¬Öô®þ}ý?ýEþèÿýagå÷ÿ¢ý£üUüVü<üDüGý¼þîÿÿÿJG¹ëù#©ýTûeù'øcù¼ûõý*qn <ë'ÿòÿœé8¤õ Ž ] ÷ ! Z%hyüîøDöéô¶ô(öÑøû‘ýÿUÿÄÿRZDÿ‹ýúûnû!üný,ÿŠx”÷(ÿýZüZükü‡ü„ü_ý­þÀÿvÿÏþÅþ_ÿB­qHÿZþáüûú?ú2ü<þ³ÿ{¢Œ® hp÷Æÿƒiš'ü<\ðMÞîI{ý5úaøÞ÷¬ø‰ú1ýHÿýÌŽõͺ­þâý­ýáýÁþß(ÿ£Fþ7ýêüüŠü üåü|ý þ`ýDüÂûÔû¦üOý¾üºûýú úØø°÷™ø{û|ýòþr[N tÊM1À¤RÔ÷uíB àÌ 0ÿ û/÷Lô€ódô*÷ðúþù¡LÙù­¢$ÿ£þzþÙþ®ÿVo$Òaÿwÿãÿ·ï\¿qôÿøý„üïûüGüóûÐúúÇøJ÷Iön÷qúèü±þÌLº1¿ñ‡VÿpÃÚúÍüq%à‰Tµâýú+÷=õ²ô‰õe÷/ú(ýYÿGjøzš%êþìþÿZÿ÷ÿÐP+âEEDwÏNš‹N^þúü]ütü ý¦ýý‘üXü(û7úûJýŒÿÛê%×Q Jò&5+)”£¶°†£!xüùqöçôöô örøñú#ýÁþSÿ÷ÿí¼ \"5ÿ´þ–ýXüjûŒüÀþ¥ÿ[þîýfþ þŸþèþQÿ9àé"äþïý‘ý\ýcýYý]üáûdûú¤ùûÛýh%ë3ÝÍ  æ“V’rÂÞÔ¦¯NˆRþýùiöúóróƒô|öSùUüŽþ°ÿ=Ò¸i€Íj²1“º¼»#½ýü½û|ûüúØúEûÔûPüPü¾û ûûZû¼ûüüŠüßûêúù­÷ÎøÙûÿŽÍw£    E˜ 2¬¬¥VÌÍíÑ PÑxœþ¡ûaù\øtø7ùVú%ü‡ýsþYÿŽ[eÅdÓÈâøÿJóÍYÿ¶ý¡ý¯ýeý™ýgþäþÇþþXü\úÆøødøIùŽúû½ú2ú²øÅö+÷|ùXü)ÿ`Nûn Åѳ©‡ŠlßLHާSÿfü]úrù’ù&úÉúUûsülýuýYþKÂ{ÑC)ñ®gÏõ“+Høÿÿãþµÿ¹™qÿêýPüÞúùùFùŒù:ú’ú‡ú¤úXù?øªø¹úýMÿsÒíä¤M‰íÅÉ}?Òq¼¾¡¢ÿ¸üâùøÒ÷ ùû.ý©þ.P‚ÿãþTÿ¯¾Ô2miMã[ÿ¨ÿv°>†ÿˆÿæš^–4P€ÿ½ýeü}ûû>û$üý°ý¯ýÄýžüüÙüîþŸŠ`‘2Ž,æ¼RæX]ñÞ`±'Ýþ†û§øùö÷Fø+ú’ûVüþÐþ‹þµþ‘ÿ¹$vÑÿ¥@оÿoÿ‚o¸þðüBýfþÿQÿ8VU±ýûûyúùZùLúzûÑûîû)üqû{ûýgÿ~KZm%»½S+{9"Ÿ @+RÙ:Æþ¨û%ùø-ø‹ùPû¬üßýÿ9ÿvþ&þÿS}ï,R(KÑ ±NÐÿnþþ—þ©þ»þCÿ“‚hQþõüžûìùxøñ÷´ø\ú)ûüOüpü)ýßýÿÒŠ»QÔËÙg“¢¥ô?FÇ]ÿHëÖýgùäö‡ö’÷¹ùKüþØÿ7 ÿ3þoþoþ þÿ˃sF†™éŽÿ:ÿíÿÙÿ mLßiÂ"ÿgýÁûMù7÷ögöw÷±øœú£û¼üIþkÿ^Ó‡‚é« ~X¶%øÓJ·hºó„ \ÏÿŸü÷ù÷ø£ùçúAüeýÿ£ÿ…þ†ýuýžý¤ýŒý*þÒô:Kœ¼þ^ýþ÷þMÿv_§Y-Prþcü-ú9ø÷,÷\÷_ùBüþ-®±ãõPº°þ`þà.  Ì÷â»ÿ¾_Íÿ"þ/ý€ü®ûûûúüØý[ÿ´WŸþ»ücüÖûRûsûNüáþã7áaŸÁåþÏýhþö¦¦çZoÁ¡ÿ{üeú£øÊ÷òöæöø¹û(ÿb§0§­aˆÿ¶ÿàäí·ãLʾ<V…ÿý£úÎøå÷DøNùHúÂûyýAÿgSzþµüÜú;ù¦ø²ù$üºÿ¹FBµÌ‘KÿûþŠçR5&™°Ÿîÿ¼þý•ûáùFøöõ¯õ½øMý˜£4 ÊAÂV< â+ Ä h <u\ QÝÿwþ¹üEú-ø[÷1øùúOû¾üîþ«jÉKÿóüúY÷iö\÷úŒýÞÒ\B6ã‘ÿŽýTü¬ýZE€[OùÁGDþëûSúù2øøø-ùóûÿÙwç™ Û<Iã  ÿ Æ-ÌS¤}Mþ|üúÑ÷Pö=ö¥÷Jùú@û4ýÿ²ÑW>ÿýêùø–÷UøwúŽüµþ­Ç¹ÿÏýçüžüœý_Ñ;—†ö⢑†ðý û ø‹õþó ô¸ô±öüúãA j Bm{]b•YÀ ¥ #  4ÒéEòÔÿ#ü6ù˜÷h÷8ùÚúEüôý6ÿoÿûþZþ5ý°ú'øÝö’öÏ÷áùÃû‚ý†þ¡þ=þ%ýŸû]úïù¯úÏüáÿÛÓOVuÿ'ýãùIö:ôaóhóÿôÝø¿ýH»i+ \ ´Åãß_ÖI ô Å w | ¤w‚wηMÿÔýAý>ý(ý™þÿÿsXjÐÛþàû¼ùµøùúNüQþûÿBçÕìþ¡üÈúƒùú“ûþÚÿŸÿjÿLÿÿ+ÿvþøþÜþêþ ý²ú>øºõQô\ôqõÅ÷ûãþš£‡Ê¨†ƒ®ÿNx$T¤x°­y¯rþû¤ú üÚýÇþ1Vÿ®öÿþžû*úÿúZýšxx×%‰þ"ü]ûsû½üÿ CIÁé‚ÿ"ü–ø„ô£ñ‘ïÙïµòfõúYþå‹€®cÿ÷þëåçqG?/¸J<˜Áûÿÿ”þXý’üüûû(ü‘ý¦þíÿk•ÙrúÕþýýý+þùþ`ÿ¨ÿfËþÿüËüþ,Zl¯ Ú éájžÿPýÌûû´úûúÄúoúKú€ú“ú„ûoüoý0ÿúk1ÿþºþ]r·z%k§– w&mÇþ‹ý(ü^ûù%úþøÇø±ù>ü ÿésSÌyðÿ ýÂûÆûû û†ü4þÛ Ó2SàÂÓ˜«¦¯ÿ%ÿ:ÿ ÿ`_y†³ÿcúàöwõõô³õvùóüî[>¸²Ê\&9WWsúO&û^†Åüjú³øâø½ø›ùŒúAûGýÏýþòþ‘þÃüeúù3ùWúKýgÄ; ñ•ÒÿLý'ú2ùpú‹ýî1÷A1#’éßýHý1üÒûSü¬ûÐû³û„ûýµÊ \Toµ,ÊgbÎ'®Bo{ª´|i¿ÛýÉü~ûþø˜÷¤÷ëöö·÷~ùùúýîÿ&oÖ[©ehÏÿ5ý«ü¥üÐüDþyþ±3´] ‚ÿ,þ!ý¾ý5%2aÿçýÆûÎúû¶ùbùZúÑüÐÿköVÿ—sðþæ p … * û h «$ÂpŽbª”þýÍùø¢÷‡øâùÂü)ÿ+ãðŸý/ûJùÊ÷}÷Sú6üLÿ­Æÿ¸ÿëÿ‡ÿ’üú+úZû˜ýÈFô ˆÄ1ÿýú°øÙøµùûnû4ý«ýlý~þîÿò®ƒTavƒ`£Cü&ÃâÿÆþýý3þ×ÿ0IX"¡Dþ¶úoú›úåûIþÇÿyPÔ=ÿ‹ûùú‚úÏþ½k: [Lîü<ú”ø)ùÌùûiùØøJ÷qõAôõOø6ûÿ뼈ÙFƒüRV‹ï=ØË™.)‘»QÿŒµkÿ8ýìû‰ýÑÿÙzÆ!ÿ-ý6ùµ÷ø†úÒþIî˜ìA{j„혞ò–þXûÜ÷¸ô‰òíóóô÷bùêùëû%ýþ&ÿÑ2þÿhü_:`[ÿïwÿK¡æ÷[Óù‚ƳýCû0ú'ûÞüªÿ£ÿ¨ÿ¢èÿ¯ûÔùÎùdúýÊXÖ­oxM> ¹b=¨TÚ¢vø‚ÿ¾ý]þjÿ¥þÅÿµÿKÿ³ý4ýpý-ý5ýƒûýnâ—´*¢ÿåýšÿóÿ0«Ÿï¼2û†KþüûäúûuýêýRü;ýùý©üÃùéö§öøLùý ÿ¸fÿX½©‹»ÿ†ƒ•a3`cÃþ°ÿ·½5žŠ›¶àôÿiý˜þ„þ^ý±ý/ýâüÙüÐþ?jF܈5   “ %¦Ýîq1¤'üÁøBõ.ò òBózøÅüNÿ‡ÿ["‰lûÏùðùJû´ý³ÿ(ÿ/ýýHüÅú¢úÏû(ýYþí@»6ÜDéÿDw&qÿ¡þþÚüŠý‘þàþ¶'€@ × ^ ¦ wÙTÔ“¦S‘â"ýDú×øØ÷‚ú ÿg:Í8+=¤¦ýùú*ûþû2þ-ÿÎþ6üMûîúÉùçøôøŒúŸú§ü^ÿ žÝÞkFÈ]¡àþ<ý–ûàúÇúû³ûžü<þ%€IMú¨åãþoþÜÿ-·MIÌ6(5þeúø2ùÝû˜>ôµ""_.Îÿbü~üoýlÿ8”Iÿ?ýÆýRýþ÷ý$ÿÐþUÿîìoIþìü ý}þ=ÿ2ÿ‹XqùlÿÜü¾ûkû¯û·ûHü7ýÐþ$IIF|€ÿÄþP ù\°“’ýù>÷cøû´ÿ[‹ÃÜ/kâ¼Úþ`ýÖýÖþö½ÞÿâüÌýàýãýzýáý²ý`ü;ÿ[ÿBÿõýZý‹ýûþ²&›¡e,=×9éÐÕkEx’@™ïýpû§ûþWÿVÿžþVÿlþðþý‹ù9÷õ’öNúúý×Á•lP;¸›þáû€üÃýlÿ¥õùýóý‡ÿiÿÙÿhÿ!YþG¨þü'ü üþ5ÿèý¸ÿ¯ÿ»ýëýdüÀýwþÅÿ7 a±å}Yú@Áÿ,ÿ •¶ãþÂÿßÿâþþLûjùu÷öHúý¬)r¡áÕh{ýeüÝüèþÂY ÿjý¼ÿÍ pïþëþÂVÿFþ^ü~ü/üþÀûĨþ³ýýÍüfþèþµV (5’  Ï '³VO"-’þ0þ­þ…ý ý û³ø¦öÙõ[ùOû’þèöÞ—t)ì÷ÿû~ùû£ýD#Òÿs Áˆÿiþºýû°ýˆý+þ‡ý§üßü|ý‰;ÿºÿ\þSýý#ü™ýÄþm]L…ÐÒ0È×qÿ×ÿn6A?k^Dÿ×û*ùÜõ-÷qú ý·NŸU ,> ý!ûöûbþ¤·ëœš$àˆÃD\õýý,üiþŒþ8ýpýýÑûû¬ù¼ùFú=ú'û•ûnýÛþÆç¢h0œì´¶Ær˜eù«þpü¡ùlùfü*þ4E"´)üý¾ú;üaþ¨©šS+R•MqbSL1ªÒ»qçŒ`ÿþ1üŒû¯üYü¨ý$þÿиînu jüÛù’ùòúvý¡ÿÌþNÿ_‘ÿ>þýúoø@öÔôå÷•úý­ÿ—ÿÇÿ&+æ„ÿ¨ü¯üþDÿa§}þëÿàõi…OG‡è}˜ÙU;“͆!þ>þn‡ƒþÞ”JŠ`”àÿIþIÿ|A´IÿþÄü«úNøö[ôÈõÿùØüãÿ·åÓ„Æÿ3ýù§÷“÷°ø>úáüþ§üý=þ&ÿ¿þmÿÀÿ8ÿ§þZþHÿÂþÏöº©KUÀÿòý ÿƒÿ«Ê‚;û+Õ@XX{ªTyÚAÿÂý:ûQùê÷uø#û›ý ÿâ?"‰úM-þTü¹ûMüü”üÃý¯üübüþæþoþÂÿöþõÿ)³þÌüþUýûýCÎ{þâü ûÊûmþ"ÿàÒ:†ÿ*ú`Ê<x’¤ð½™´¨¡ý9ü9ú$ø¡øéùÕüÿÕÔ¾,ðô]Dÿ—ýµý=þCþƒÿôÿÜÿ˜ÿ!ÿ?iÿþ°þwþýˆýúû¦üˆýZþ¿®û5D¼þ5ülý/þ#Q¢±\“7—©•ÆR&ŒQJÄþ[þÇý û2ø[øÙö–÷úüxþÿjss9•ÿÎü~ü!û ü:ý`þ®ÿYê†ã»¡¬±·þþcýVü@ýUýŠÿ nhM­çþÜû,üüýöÿ-6Û»Ôb E™iî¾K_•Ö¿ÿüNûéúIùìú­ü¬ýÞý7þåþ²ÿòß#ÿqþÀû8üCý$þgÿÏÿ°ÿTþ‘ÿðÿ¾5‡ÅDñ<ÿ‰þ^ý,þŒ'vZðý¯ûDúÅû$þó’éÈ9¼0=»þeýÚþ’!eå¡G ÿòûAøŠö‚ôKôœøûCýEý!þÁÿ´Ö ÷ïXÿËþ7þGÿµKIÿþý‹ÿ_X@ ‰3­wø»†ÿýkÿGF/±‹ýyúq÷³÷Äù®ýsh\Xø(ýmüˆý±þO7™P¼¼&þpûLù5÷Òø—û–ügü"üBû?üý~þŠ%Y»ÿi†1“þ½ûOûgúoürÿnU¢6ã´ŠÚ¦~пêLŽPýÅú—û&ýrÿŽ+…( Áa9ÿ†û úÇû¦þÜB"¶B!ÿûýøølö—öüøúû÷ý/þ=þœþ7Ž.¡þ°þ!þ]þ˜þÁþÐþüýÐüþÍX,÷JïMaþãüïûtú'ýÎý&bêÿÛÿ^ý¼ý$þA8Þç"ÆÙËìýDûÊû˜ý2Yã稩¼ûùPøöÔôJø'üHþ˜ýqþ¥þ¤ñÐþ;þ~ýyþÌþ c—(ýn›½ÿ,=ëÕ£[7üý[ýýÔüÿÿŸ‚ã÷ÿ‡ü•úÍûŽü°ÿÆ 5ǨÙþ ûtú.ûºüùÿ¨.>]¤þ“ù{øt÷!ö’ø`ûVýôüJýMý‹þ:ÿÿŒÿéý?üüNü·þyÿhþªý8ûØý[ýý±¹4 À  æ tuÿ¢ÿ£0ÙK þû0ýªþDR‚ÌzèÜ9Þü©ú¶û ýÂÿEÛƒ·… ýƒ÷Tõ²õFôEö]úþ9=¸÷ÁÓÿçü7úÜùiú8ü ÿŸÿàÿRýýþŽÿÁ­¥¡r "ꚪÿ­ÿàþþþŸ'¡8 %:þ%þ49Ñ·Ï  eÌR³9ý­ýÌþ×¹‹’ÿNÿsüì÷ÌôëõnõöÅúTþîÿ)þ6ýÍü%þÿŽýÉüaûcûmû9ýSn ÔýÇü÷ü ý2ã¡ð}Ùž·ÿ]ÿOÿ†ý]g-õ;ÀŸÿ‹þ|NâsP} ñâ|ÅüßûwýoÿÔ2è AA¶þƒù‡÷Œö­ôq÷ƒúýýSýÉýÖþDmSÿýŒûeú$úiü$ýýÊùwù-ûküb¥V e  5úböþöþÁüdÿÔ˜‚]âBýüútüãý@+xÿõµ[3ÎþaýÈþÌ£`IÒ°q™ýOùÕ÷¶ø‚øµûïÿîÖ hÉ3ÄÿìýðúŒù4ùíø®û¦ý»þ–üû½üAüùÿ¤ð!Cç— ÿúÿáü ýq5µŒÿ¨üàùûãü ÿO”îÙV¢dtÿ{ýqþÒãt@TœéýàøØõdõGôõ|ù¬ý¼þAþTÿyÿßÜœKþ„ýÿü`ü²ýÜþ€Iþüæýþ×à*: Ût qfê5þ†þ_üfü+1–îþ0üëüºý¨ÿ‹IqY¡WÿüPúCûýc–Ô—'|ÿ—ûöøRøX÷þ÷~û•ÿÁ¹ÿKïÿ*K´þúüÏü–ûGýHþîþxýúÙûHüîÿzÖŒ'7c H9þzÿ/ý%ýŽÍÓI²ü˜ûü÷üãÿ×3 ˜Ünsÿ×ü ü~ý'¸CTÈ­þ4ú÷ÙöÍöø±û7Ëfc?;ml'þ¼ý¹üiýÑþOÿTþºûýPý­ÿ–9— @½ÿý8þ”ý’ûÿ®½þ ýXúJúNüµýËw¿Y¹ ƒšÿ²ýÙú§úQüwÿQjlÉôþ­úÛööUö²ö ùþîÂmû‘¦oSþhþBþ"ÿÇ¢îþòÿ÷ÿ–Q£y½Êk|ÄÿîüÝÿ.»QõÿÄü®ûüVüþÍÿq$×ýuÿ²þTüHùŒøùù„ü4ÿ…Ñ£dÿØýêúløÚ÷'øøÞú^ÿ¡m¸Öûÿ2ÿÑýGþÜýMþóÿdCý4ýiý®ÿzbÂÀOP[àìJîþ¼òé ¿-þxþ·þÈ„=ÀFúþËúÔùŒú'ü¸þî`Ôÿ3ýÛùèõSô¾óó¬õeùýîümýýºýŠþHþaþfýjýý-þ“ÉDkþývýÎýAbüÜ}ð‡]×£²ÿ™R‚¯­Joýøý×ýHÿ jº øÒýrü ý;ÿ©7Kk‹ÔIý)ø¹õfõ~õ÷[ú{þWÿÖþ=þÿþxýØûëúWúpú¼üþþÖü]ûšüUýì·Òfv©ÖÏÓÿþÿñý®þ&S%}ÐÈäýŸÿt‘‘…‘e3 Í“¢þqüRý÷þ´õæÆþ·ù`÷u÷ÜöÝ÷•úiþ‘ÿeÿàþ6ýLþ þ9ý‘üÝû/üü¤ý5ÿÿ<ýkúuú,ú‚þN¥÷WLáO;<þ_ÿ¼ýžüõ›;z+$ýÍýþžþ`š€ÃYEôª6þëþ¦²úQá^+9ü¦ù•ùëøù}ûRÿþËìÿÜ£ÿ-þ<ý½üŽû¢ü ÿOGÿÕüdý[ýÎ"¯ÊóŸ"+þJûü¡ûYú™þ_õ?l¥þŒþßþøþquü®*›üþ;ýÊýÈÿE+Hnðý¾ùkøø«øsûbÿ ~?¹¼°þÁü,ürûü«þzÿ`þVûsûPû‘ý۵ОÃkP¿ÿ™ÿnÿ…ü´ÿ-y®ÿüxûáü5ý!ÿ@îš=¼s„ÌÿoüûUü±þùäÜ9æÿ~ü¾øøÂøùKû¯ÿ’ ú§'UþŒý¾ü>üÆýÔþgþ;ûöú(û½ü3ý<vÕÒ2-ÁþÈþlÿ{ü,þ@’Á§¹ìýÕü þÚý¹þÐE*~¼R¼P+þKýâþr.ǧ‹-mþúø*øˆø2úÒý©ý÷ÆwuÿyþCý]ý+þÔþa”MRjÿõþÿmØJ²õÞó´ýøüwþ­ûrý’`¢E×ÿýû,ü[üýiÿ‹¤Ô£þ7û•ùµú)ýIRxGnµoþpûÀùxùbùÏúRþQ‰ûïPzBÿ„ý@ýöüÙü‰þ”O‡þ|þÿl×ü¸ ^ • I RóãLÿ°Ðýþ¨éÍ¡þ.üøü'ýcþÃÿ%x«>þ¸ûùÿöâ÷ú#ýÚÿ†w\þü¯ù”ö·ô×ô{õv÷…ûyIíÞ’'Bª¾ÿôÿfÿhYžÿyþ`ÿGÿ#ù>ð= µÈSì~à @Øü›áý†þ>þÙþq{‡ÂÿÒüûyûÿüCÿ–eÌzÿKýú£ö‰ô ôCô¬õQùËý¯þWÿŒþÀýý«ü û-ú›ùúpú#üãþØÿ,þÊý"ÿ 6÷ 9‡)>3%³Æš @ä9Í73… Þ emXMÿŽü¥ú¨ûUýöÿÑßÙÛæüßøRö<õÙôÈõìø`ýíþ.Öÿÿmÿ©þžüÝúsù“ù2ùžúþüšýåûübýÏþÅãÍždXÖ$ÏþýÀþýˆþ2÷L»À7Ôh¥„õw(DÒ’Fsÿ?ýDþ0YHQHßUýÉù‚÷öIö=÷îú¶ÿ?HŽûŒiÿ(ýOûbúŠúYúqûþœþgûû™û¬ü±{f_‡þ¯ü”ýBüÞüÊšC¦Ó KÖÿkßÇcáJ.Èþ¤üþmgdc G½X‰³ûë÷F÷®öÞ÷ãû‡G˜pÿuÿŸûPûÊüû¿ú÷ýúþýaü®üæýc.èúlÏ!þëü§ü+ýxüaÿvùÜvYþMþ³þ}ërô° 2I®ýnûüþ ‰Ê-FþfúÈ÷fö÷yùÈý˜X!Ž»|»þ×ý~þfý¨ü|þ8ÿýüZü×þHâö V¥Yÿ=ýVüRüMþ?þCZÐÿ»þq‚@Ý´8Ë,>ÿaüzúLûyýa7†j0ÿ<û´÷Uô1òµòõÑøyýÓQlíÿëÿK†ÿ-ýõýŠþÁÿ’å+Ð#1ÿùÖûø+Oäÿ/™*•¾@ÞrXþ®þ[a‹[^°dœ­ÿEýÍü+þáÿ˜¾®wäýúq÷ö¸ö¶ø‰üþÿùo÷³ÿêüsútùTùSùdøÒùüþÿZi¡š/Áÿ>ÿ®þ.þÿü¦ý¸Ü4¢`ÿaÿ+ÿàÔšË ­ ~èÿþþÿ*|›YãvþÉû ù÷Ž÷÷úäþYŽzœŽ0þFüMûÌøÃøpú¦ý@÷Eæ(þ{ý¯ý´ýRÿ˜þ¿ýÿ÷þùþsÿ)Ëþãücýkýþ/›]Ô•ÿbýØûçúÿù@û¿ý5ÿñF¿ *þŠúœ÷õëóyöÔú+ÿ$=1  m ˆOÉóüòûü¦ÿ²–)¢) Ybõcм>ÿA·ÿ¢þúÿƒ¿òÊÿþt%‹¤&mÿaû)øuönõöEùTû³ûýœÿÖÿaþý˜üùù±÷¼õõ¥ö¦ù%ý1ÿyЗzÂN ¯þ§ú±ø×øEû¬û"ýsÛ cóA¸aê¦ ëlY ÅùÕ„ºË @ È £:gÐü©úùÍú}þÏÿªÿz xÿ1ýhúÔöwô£ñ¨ðîòþöú´üf/+‰¾oãÏý;ùŒ÷z÷ÅùÓø%û1þ†ˆ§£ pmtp¢ÿ|ÿFF eþ1ÿä %Æ á ± ‹ƒÅ"ÿþ]ý ÿX{z=¶5þ¦ûRøHöõ/ôõ ù’ý#‡(*Δæÿ`ü®úkû{ûÐù<üRýáþÿŽkŽrjTÿ ÿÿ9ýPþ–ÿÔGCXÿãüKþ€ÿ¿ M û ®þüûBûŒüÚB…3'ë‚?þèúÖö@ôèòLòwôùØýºÿ>ËÐg2ãd'ÿý2ü‘þÁýÍüþÿ‘ÿ…WˆÿpdïÿaþÎüÍý þíÿ›ÿ•ÿEýðû/ýVýÿNúN}”|þ‘ü®ûrû€þÏ›#´‘½þ:ûO÷ÃôyòÄñºôòù]þ)Q\‰AÌòÿ"ý$ü×ý„dÿBr·Në’Ò›o6Tª|ð% ç(nýwýŸýÛýÅÿ ÒWyJüùìö3öö¤ú`ÿ½aR~~.þéù=öóó2ò·ò³õÖú·þØÖ¹9 Ù^sÑRÿFýû¿ýdþþªuØ £>E¦eCÿc:±„éoyÿëõDôÜ ¾AœÿGû<ø´öö(ø÷ý  uö/æþªúÊõôñ¿ïzîBðåô-úÆüàÿW!©MTal©ÿýYû‹ûjÿËþ5oÍÏ÷>µ´scÿÆþeÿÆ}TÝnÃÑ4„ bÿXû×øÆ÷v÷{û§ûÊi¸ŒýÎ÷2ó,ðiî˜î òÄ÷Dü×|¤p}€þ üKùûý´üÇ4¾v¥aF3à\ÖþüýËýÿôÿ²KjeåæÜ  Ð%±ü¡ø9öºôßõûzÿTƒ®1’Ëüi÷úòòï¤îoð4õûBÿ/Õ¿ å²=øÄýUüŒûÿÒýìþa­‚K¼"˳üšÿ‰þxþ#ÿÎþ:ÿþ8ÿô8Îã ×, h˜Éü&ùùöVõõ÷ý ÿ¼®ŠêXÿ^ú†õ‡ñkîíDïmôùþãTC%}W§õýgü4ú±üRþÕý›ÝÆÚֺ̇%ÄN”wòÿ ÿPýÿ‡ýÑ8ºú ?ÿmúß÷ö›öªû…ÿÝÔÁtÀQVûìõlñîìñì’ð_õìù„þ2ø“|‹Ghþ”ûFúvýîûàýÇÿ®¾jÿ(^þ9ÿòzJúZÀÏX®ÀXÿ«ÿ#+ÿ øv ] ~°þûù!ø¢û <ð¶$ ‹ÀÑ‹û_öcòÎïˆï(òö‚ùéü‹ÿ•JöY:â–ÿzþÁûTþdýãü7ÿÒÿ5ÿ þÎý}ÿP¿Š”6cÅŒtÉÿ>þaÿ(‰á g (_þµúÂøŽ÷Wù`þÁ& ê aÙìý%ùÞô¶ñ9ðçñƒö„û¸ÿ”ÐÎâaÛõöçÿþ›û…ü§þ8ýãÿ4b¿V~ÑÿÃ0^¿q\Öv2[ô»þíþ×ÿ}ì à Òù&þÿùO÷òõ8öÄú@ÿ»%ÿc¶4gþÔù_õëñ]ï£ï ó‘÷qûQÿÕa~ov" Vÿjþ‹ýý´Ÿäè·×ÿÃÿ˜ñËø|NjÝÇÒ­ê ¿V Ƙôüeøéõ'ô¼öüÿø ÷¸†-8ü@÷óšïÍíaï–ó øBü"~/"¬Z!ÎJþü&ùÛû ýý5)gÃT Í¼X R³ÆMs1ñ‰üY÷ g× B@÷ûoøPöõö[û'ÿäÍŒr{ýø3óGïÆì„ítñmöžúKÿxàÇÂÇATþ¨ûóú'ý…ûæýÉ£ôÜUdEª›ƒS“þ™¨¡nÿCÿ— O ƒ¾ •{ÿAûÏø÷²úÿ‰LEm[Žßû4÷Àò&ïtí1ï$ó ÷*û¯þo3º˜Š7þÇüú%ýÎüîürÿ„•âcä¼:©×T’_@>ˆG /áØ í†œûƒø´ö’ø™ýÃ,@óÓì­þ:úuõ¶ñüîiïdò~ö*úÆý:I]à±ÑØýnüóùúû`ýIü½þßÿ\3öÿÇþ¯¾0ñšÑÃòÿVÿÔýjþÖÿÖ " †G ³„2þ=ûWù³ùþ™»—2Qº7ÿŠúIööò³ðyðóZ÷*ûµþé—2Ó(º Ðþpüûaþ-ýšþ/X Ÿ ÿÂÿ²Åé˜Ö-òÿujÿ4þoü„üKþMBŠ ª âÀŠýQù‡öõPø¯ý•Ü[ ÎvXäü4ø¤óîïî ðÄô(ù|ý62jZÓóW1×ÿ†ýòú×üüÝû{þ½ÿ¬  | Y@p¹mæ\ˆFåÿãÿßr[Ô Ï¶þßùsöcôöZûJÿqƒQ´oCîüÏ÷6óÛï¦íîœñöÇú<ÿ òôç3¾Î1!ÿ!ü(ý_þ7ýæÿc¶ýWªÂSSô{Áÿ;ÿÌÿ¤æÿJÿŽýµýÿ*EC ù « ·äLü¾øPö ö<úœþèœ"´9¿SJûlöiò3ïîð¬ôãø”ü|Ðm˜Õ·"þ•ûÐúeý¥ü6þýƒ%2­³*~½4ºŽo° ÿjþNþKt33 9g {^þÅùöôþöûíüŽþÜá'”Ó²üù'õEò³ðÚñ;õÒøü&ÿܵÆÉ­6™Åþü!ÿ˜þþ T'™4ÿ!ÿ´æ-xª~³0ÇðþGýúûÿü6ÿ[ EÊg  ¨Ùüœù÷søý!¸œü3ýãøŒôñï§ï9ód÷²ûwÿÛ+í»t|ÈÝþü&ý]ýäûÒýžÿÊ;Öý}`Ów\è%H3˜ü@“þ ülüný?ë§ 3 /é¢üØø÷õÀõBú%þ4òñÒü þ2ùÄô1ñÍî›îéñ9öpú…þ}mH>õtGŒ$ÿÈü[ýfrÿ57$)vÔ Æxîÿý éÿ»ý¹üý­þç¯ » b †–ÍýkúÂ÷Cö ú¤þZsÉNnû*öRñÉí&ì¤îyóLøýT®ÿ¶Æ3Ž%ÿñü»úýëü¡ýºx·®5?Æ”±4f¥ÿ!ñÿßýKüžû÷ü”þ6Çó  = gÛþAûFù«÷Áúæù‡¸) iuý+ùþô€ñKïÓïô§øìüt¥Ñ$i‡LþrûBý³ýÒüÿ>Íøƒçåÿh‡R·zOv¥ÑÿÓý]üèûîü’ÿ:’ Ö Ñ { þ‘ù÷æôòõ™û-'úSÊŽz²þùõ”ñÂî[îsñÈõ@úŠþ H ” xÝi?õÿ¨‚ÿªí–)»ŒLùmx¢RÖOÂø‘ÿ»ýPü“ûýÿ‘[  êÀÿù<õ òüðrõµúÏý¼#çZôçû,öyñ*î›ìÕîfó ø€ü›mJ^ÓÈøç<Øþ÷&/(*ÅÙFó4¾î~ÅÀê×›þÌüÚýêþR½ÿ D • xqýÑøö¿ó3öùúôý¥ÿ ÍÒ“¯…ûÙö´òï¨ìí‹ð‹ô‘ø­ü=¯/^¡”°žT™ý\DPÿCì»æbr2G%'ýv€e±¥r0Dÿ¹ÿø± ÆS" mÈžûùÐöò÷¦ü‚ʽg,ˆEþYù_õcñgî%íVïåò=öãùÉýœfÙŸÄQÿäüú û‰ýnüMÿ§eê§½»A­mºz5¬2|þ þÿW„G paÝ i.þ2ûñøÂø±ý†ö†3Kÿ‘ú÷¾ó‘ñÖð6ó}÷HûMÿЉ­7 Çþøû(úý>üÒýVÆ"WÑþ’þÖÿ7¥:˜·z@–Äþ ýìûóüDþ!§Ú " ¥ úáüÌø7ö.ôê÷lýÛÏR ¡Î3—ü.øôØðïOð ôÿørý^ûRˆ«²˜þU^ûþ1ºYÿãezKÐY•?XŸ"a²E.ÿ-ýUû²ûùü¡ÿ$+ Ç Q²‘üÔ÷ŒõóÈôú>þ#(@-ðü:øKôšðAî5îºñùõ\úhþ$zX‘6ÉCòÿý þ—™ÿxHÑw3Q?p½ê‚¤ëØ÷þAþ}ÿG8 ¨ ò=üÓøö=õVùýŸÿ{âÆ~}ÿWúö\ñví}ëíÎðôÄøßü 'G?ÉOÊ9ÿ~ýsöþ5§Í¡L ?ÿÿë2ÐYåyVظάþ†ýˆþ *¨ ``Ò -×ýùÏöžôÚ÷[ýÉ æw + àmþcùûôñˆî¤îò ö>ú2þ|VödˆiÔöwÿÐü?ÿÿþþ N„qú9u7çÿ›~ÜeÅ?²ÿÖý‡ûßû÷ü! ð ñ bþ¢ù<÷ÚôÏö’ûÿê$]QV/ývøÃôŒñEïYï¶ò±ö¥úmþ´6¡É;ƒ†þþüÿçÁˤ½ÔÌCB(ëPçÜÎL‚°<þöüµýmÿù\ ™ w mìúé÷uõõ¬ùoývÿЩ‚6ûþäùãõìñbîæìï0óðöûuþGA‡(QzÌþnýfü±§r¶ºWq;ÞÅâË Þ°¦ó¯&ùÿíþÚÿÁù Au ê þVúì÷ö÷ø#ý§ÿÚÒmºZ¦ÿÜú÷4óYïíÀíñ”õKúMþÈ5êUC¶ª9ýûâøYü­þhmêåôÇP÷«ÉÈèðú—õÿ0þêü/þ;W ›¦Z }‰üúÚ÷Qùþ`ãS.«—…þùWõ*ñîhí¾ïaó`÷=ûäþ%‹»Kè`þºûÙûÿcþ6NTýõ—ÿP0qC>’Wçô§ØþýMýãþG$Q Ö€ ¶ªü(ùO÷L÷+ü¨#hã ”ÿÐðüÜøùôXñoï/ñìôŠøßüin´uÐïóŠsÿÆü¦úÒý&þ•ÿ(,Ú¤|ÚÖåü ézÂT*þ_üÉúüBý¿b¼ “ îåû$ø)öŠôš÷œüF¹ÔŠv<¡CýýøõYñÈî/ï‚òXöû†ÿFôJŠ ˆ•&ÿ`ü¿ý+„rwý°Ü|F!JØ´]ua‡%þ¼û2üŠýÁÿn"  = ÷]ýÐø÷õ[ö$û™þ“Ÿ”JdGsüÖ÷àóýïíÊìÇïøósøµü>=g²Î²Ãø”þýùü'h[*5©nWÀüÂþ·EžÉþqý·þ{ < \ ëñÙû…øÍö!ö—úÖþù;põ» Üý1ùiõôñ¸îXíîÌñÊõú­ý~£äûž ÿ¥üú8ýEþÿs¨<….•G¥qer7e=nþËüäý©ÿò­:ØF K ÿ ûbù€÷Pú=ÿ²º M]Í ûöðñCî ì¤ì ðŸôùéücy ‹4Y'Ôý<û[øèùLýJý¸Üz%t6î6¼?‰€ñ  ŸØMÿÚýðýÿ“A #9 ×ÿìùæ÷ öÓöîû$ÎwÎB . (Ç0ûŽöYòï î=ðOô³ø ý=(m¢“ÌáÏ!þ›ûðùjýHý÷þ ½ËÓk¨-‚s” {çéÿíºÿþ¼ü‹üwþ–¨a / –t§ú÷hõPô=ø=ý~&ÛÆb©üî÷sóFïßìøí¢ñþõÜúÿÐò=Ö©‡å¨þªû²ýüþÒþ}}šháoì  6Žï·JÎÉþ|ýgüDý™þWM¥ – ‘ åý·ùø öª÷qüuÿúÎf¦Olüó÷ýóbðgí7í¸ï5óI÷*ûOþ¦Þ6åVÀ+kÿýýüC~ÿ’¦ñ6qíçùY½ƒh¯ÿý‹ý)ÿ–* ’á ýIúmøÂ÷ûüþ1\ mëÿ§úöãñZî±ìîiñ>õgù¨üœÿ핪<þüúBý×ýcÿ¯Þ‚™—].¸¨¶à½H:ÿpýhüßýIÿ©2Ú Y ¶ì#ý2úòøøûctX[ üy†/ý¢øÞôtñeïˆð÷óè÷üGÿö:¾6  UþüÎù¥ûPþ=þû(JMl²àìÍð4 ÿ.÷ÿþýVûüžýZ2í z “ TÞýyùÔ÷öK÷>üÂÿìäÚÇM7¹þ]úGöËòðsï¾ñpõÀùïý.·ÖµÞÐLMþûˆú0þþX†ÇQÝ‘4Æê_\"ékÿ“þný^ýçþý• Ò —D¾úøhözõhùŽýáÿc9X©EÿÆùõ.ñÆí8ì±í_ñ¹õúŒþVUÖ ª80æþiüúéü˜þƒÿè7.wPxqr€Jñ èg1õþ}ý>ü›ý–ÿ8% £ ¿"ÿûùŸöøóüáÿ°ÊMQŠÔüû÷âóðòìÞì‚ï!óQ÷PûÉþÏàÅzýûTûVýàü ÿßÿÏ¥³8é,Á¶X~ä¦ ÿƒý¤û?ü3þ=Ió ò ^éüpú™ø¡ø/ýï9ä­Í,.oÿkú$ö¿ò[ïîµï óöÖúÔý„Ö÷•D#lKþÙûúîüÉü‘ýcÿÍÿ®òÔÝüFͰmßrÞ‚Žþ†ü»û£ü^þ½© n Bãÿý)û±ùZøÇû'-Ð^Ì ½çþoú<ö:ò©ï\ð,óºöšúáýâ§` Rr (þÚûvýxÿÛþÐÝuJ´Àÿ¼ÿbÓ9l.-ýʺ‚þÅü…úúpûþãÈë ÷^ÿUûðù&ø1ùˆý5îÃ]Ñ40ŠýðøÓôkñYîwî{ñöãú4}è¢ ó¨‚ÙäÿÑýýp½q¼úG§ôr_ÂV$>—gˆþþýyüüü^þ *F ƒ Á@aûîøÌ÷R÷8ûIÿ%­xØÆþ,ù¸ôkñîÃìˆî1ò%öÀúçþZd¯ ÃX­¯ÿýü"û»üÿJÿᫌônII Ÿ Oý½Ãìþ=þ÷üáýšÿŽ£ ó Ì fÌÿÃûáùx÷‰ø®üO.B6QDüW÷ûòGïýë^ì&ï¤ó ø¶üáÿ¯ëÑ¡ä9Xíü»úàù-ýµýûÿÁ·XIŒŒ~YÙa±°|Çåþ`þ?ýý ÿ.hS  šÝ?ýÉú!ùø~ûÆÿšýFß \ ¹¨¡ý”÷IóÇîê‰í<ñðõ@úÅÿ‚ ÌI"»iÁ.m `7üH3R¦H# x xC>ÿxýqü^ülû9ú¸ùìùÉûíþ%ŒÎ/ ”$ÿ®ü«ûšúYû`ÿ°oëX´—Õôü¶÷ÀõáòîðîñÅõ°ù*üÝÿ°  `ý –›ûPÿÕþ&ýôüü±ûsüþðÇ[mI2—J „öÀ¸*e+lª:Yiÿ0ýüýRýÊþrR¯°cþü-ûù‰øÔøðúÈûXü—üû&úeûöüžÿ²ýÙd¸ùæþ†üLüü4üaü ý˜ýoþÁþ‚ýBüƒüâþ÷Ûñx7H4ó±rM1ÈÎÿþýüHûòú%üxý3þíÿ}[sCn4ÐÈŒ´Þ‡ ÿ+ýþ’ÿ>l§mw5ÙÛŸçþý¦ûnüÖü=ýÃükûÐùqùçú2üdý›pšÇ æ  –m9ACÿÕüûîù0úOú`úÝùïø ø}÷Y÷u÷i÷÷ü÷&úZüúýÐ+ÜC>>uöýÑý2ýZýpþdÿ„ÿð‹tÍnb]Ìÿþôü4üýôþ±ÙSXþ X ‘ æ } "i þýùuø4ùðù3û2ýÿÏ“vÑýû†ùDø3øCù@û ÿ+9”i.ïÈÿpÿFÿ¡ýäý‡ýüaû¦ûåû4üóýuÿÕ4çë² K'þBüŒûµûÍüCÿQž2> “  Ü · ° mÖáü4ú'ø\÷äø£ûþHÓ…Kkþü˜ûÎû{û.übÿɇüeu±´ð¡‹ÎãýAü_ûmù‚øˆøFù˜ûõþxskëÿœýüü¾ýñþººY¿Ã‘î«Æ«ÿÌý¸ûŒù¶÷d÷Û÷øŠøjúÂüšþöþ3þØýÀý)þÁýqýÿ]2àç”AŸ ü| ] Ú#¢øþ‰üSúÙ÷ öPö3÷èø€úüyý.þÖÿ5HTÁ­ , ¯ ÍÕ&1i€ÿþ˜ý\ý¹þuÿíþ³ý-ýÑüÌûúù’÷ÜöÂöµ÷Ëø®úþa¢æ¹)qHQf€zÇn%Íþ:ý{ûiù#ùiø#öõAõþöÂùpþlv+ Ý o Ì _  ‹¿Éõÿ þmüú7ûŽý#ÿÿëÿ®˜þüêùšøø|ø‘øûZÿ–ЕØõQ¤? bºÌU7> Ùÿ_þBü#ú—öôiòoñ@ñÍóâø?ý¡ÿ_ ¥ Ò ö R áã(ÿSýmú˜øùûúÄû3ü8þoÿûþhþÙüÕû¯ú®úúGûþÞ€ÌÙtÞf0œÍÃR¡Ò ,˜9 ÿ!üGøöqôèòœòùõúøŸû}ÿWàå ¼ V¦ Tz¢ªýøù=ùâùÝúûü4ý¹û.úøTø-øcùÄú üÏÿIã_5þ[öô¦™ý™nË»…¨¹ ÑÿJþÞù©ö/õsóoòKõùúúý¶âš  ¡ â {‰ § sÖý6û«úRûMû»úÙûÉú1ùÔ÷‚÷º÷øËøÀúÅýŸG±|ƒÍšŸÊý“þ€ýý­ÿËé«{ÿøþPûì÷¯ö)ö&õ÷âúÆüœÿ©mtا |] çÈL”KÿoýaýþPÿÿØÿgÿýêú‹ù;ù{øù7ú°ü9z á¡?UÛl! €þHÿ ½ýMüÿÍü-üàø»ôëòNò÷ñÇóËøû`þ`‰ ¿ $ ‹ Œ ' Ù ÁþðúŠ÷&÷®øLûfüÓýwþïüûßùfú~úæú…ûýœÿ3–ƒH9BŸnck¸ÿÈŽ6bÃŽÙþ·þ¨üø–ö„õäô%õõø¶û}ýDŠÎS O ¢ [¾ ) Wöüõ÷ëô¨óEô–ô‡õÁ÷ ø±÷ ÷Ì÷ÿ÷ßøúwüêÿËø °Îj9{[ÿ8£®®®¤\µç<ÿCý§û·÷(õ ô`ôGô½÷ûÙüïÿlš EJѤWâ j,ÿ7ûùNøa÷Úõ5öþôIóƒòŒó­õ~÷ù)û þ§.Pmì™_ÿ?ÿýËüxþÃ¥bív´þ¶ûzö1ò¿ðåï`ïÉòSøMûQÿ®' > L IFœŸÆ VUK£ûvù-ùkùOø“ø@÷ôœòóñ¿òðó>öõø%ý˜ì* ½¨æ_f:žµõº `«|Gàÿ¾ú`õxòrðxî¾ï ôönùÿ` ›ºuWëß ; <ÒJý®ú1ú^úôøÁøÇ÷ õ6ò¿ðùðVñ­òfô•÷]ûÇ鶺Ԧ4·%è‹KnX = ­kÙyÿ þhúùõ£ô3ôàòªóç÷Yùû•ÿï²Ýß á ‡H d ·ãjþãýµþ…ý>ýøûÛøôô3òœñ~ñŸò¾óœöÀù.þ­Ö‚j¨ij^±·ê , à § ;pý;øçñÝîÂí2ígï‚õ&ùIü ú Ï ä   l e X »z‡þ”ýMþ€ý[ýÐü\úm÷õØôÒôRõö¤øóûÒÿ–6™ê:Q\i-þçþVÉcƒ 4 › 3 .E<ýCöpò ðdíêì¹ðLó‘ö®ü‰| ˜ ’§Xµ — I»ì¨þüšüþ þÊýêüúgö;ógò…òÛóö°ùîý¥–WÛì]…D•ÿžüœû)üü þ9Ó ñ '¡ ( Úþeø½ôÁò·ððAóWõ÷$ûÿØ> ™ Ñ“ – žW®ý}ü!ýÙüübüQú÷¯ó ò òñòËóùö)û;’úñ$d¤|+ÿ.ýðü@û:ü÷þD°ëÓäx=ÿÎøÏô³ò£ðÄï§ó™÷öù²þ~Ž–Á g í ¨  @ O ù®eÿOþöþôþþNývú¢öåò¹ñ•ñ ó’ô=÷tû™ÿ-ÇQ]à"Êpkþÿþxÿ1ÝU …  ÊÿýÇö«ò•ðYîËì‹ï,óõoúTíþ< 0 L°Ú  ™ Ù£þßýCÿ‡ÿûþþ÷ûˆøtôÀòTòóAôœöïûÀÜ Ü÷ëš#þßþKþ.ÿ'E¨ – 3 ™ KØ€þ>÷èñÌî´ì+ë î–òÔô¶ùçþ3m T ß Üäe0 ©Âتýµû&ü!ý!ý8ýºû®øŸô˜ò“ñÛñ²ò³ôåøýíiÊeª2ǺFÃÿœùÿÂèç Ž & ‚ E·ÿáøIóØïsí€ëèì/ñýó*ùsÿ ö. 3î ]°ö ñŽCôÿÆý³ý'þ#ýöû!úK÷yóeñþðTñVò«ów÷Dû­´8ò1ÜUæÿ¤ñ¿­Ää 0 x  Ð8-íúAô”ðôí³ë^ì7ðRò½õDûa f ·õ°)é. ’6ÿÞþßÿQÿƒþMýãù±õþñ>ðÔïñ,ó“÷³ü5-<ß™Ng¤ý]þïþœÿpÑ J ø ) 2Óüûõ9òïìäêeîcðóøˆý§ú  Œ=e8 z NûÊÿ~þÿ{þÅý ýú½õ5ò‚ð´ïðëðÓó±÷ýF¡-sI—rÏÿ$ÿñÿlÿ›vã ¬ ØÌ ŘÞþì÷ãó ñÁîþí1ñó½õžú†ÿÀ9ˆ  G h ˆ ²Pu%Õÿ³ÿ}•¿½ÿåü­ø°ôómñ„ñ×ñöóW÷ûºŽBÿ¬ÿUÿg y¿ÿÿj&K,» A ƒ{* ÁaI¹øñóBðOíåë–îò‹ôúÿ+°â Î SI¹ü  ‘¶™Wý¸ûýIþwþÜþ+ýÈùðõ3ôºòóJô¶ösúoþâã×µfaÿÛþ¤ýµü\ÿYFf^ V F!^ ™ùOôäð4îìSívðò’öôû¾Íø! #dD%* ;Ôƒþ!ü‹ü#ýü´ûµúÁ÷‰ôOógò˜òróAõÚø§ü˱­vnUƒÿ¿üÆýÌýEÿ£f‡ Uü„# ŸŠúôAñ{îˆìîò?ô™øþs  h £zÛ| „ ¦>ôý?þcÿ†þ¥ý üDø—óñ#ð„ðpñ!ô÷ûÛÿèé.ð‚GC`-…˜Kr­| 3   Þ §5Içú+ô±ðEíëÆëzïò`öüüB< ,xÌ¸Ú × Mê»þ^þüþWþlý´üÐùßõÕòyñnðæðÿñçôùðþ?«®C—þhØöþóÿ0£±¶” ù^Y Ñeü[õþñEîxë÷êÂíèïÂò¨øˆý¯à ¢ öî¬ç¸ ‚ jxºÿ¹þÄÿŽÿPþŠý`úœõÞñ®ðæïªð‘òö»ùªþ5Âgá «‡BmÿÁmÖz  \YåŒ ¼&ŒÿÃ÷Æòï ìEëîÑð óÇ÷»üÉ«K¥ 4 ¸ç÷¨ û Ü´Õl3GšÿÁþ¤ü"øÔóòIðÉï³ðŸóÜö€û±fÑ/àÇ'2$rŠâ ¼ á¢Ð ¢‰ù«ótð&íwëGíýðµó‘ø4þ´-ÞŠ ô ç˜ T 9mÒÚÿRºþäú$ö«ó]òñò·ó£öú›ÿ€%¯b|Éÿ(þ‰èˆ;Ð öŽæ¦ Y Šãú·ôxñ¶í%ëÝëïñ&õåúÿ9{Ì 5ËK§‚ |þþ‡ÿ!ÿrþ,þSûÖöûóÌòóñ”ò9ô±÷$û†‘*ñÿõþ›ÿ$ÿ"ÿÛý ÿâ/ùñ Rzù– Ë&Üþ÷Îòžî¿ëìÌîˆñÜô–ú^ÿ¯EÁ ­ ‚qdå m ÃâïèþÀý²þjþýŸü×ú<÷_ôÏóøòó²ôƒ÷VúÄþ°5;OÐÿ†Ïÿƒÿdþ˜þsè~Þw }± p `ôUÿNøµôñsíŽì^îÏñ^ôÊù[ÿþóâ àaDÕ ç _ŽÀ“£ÿÇ!3ÿlþÛüùÅôØòµñRñSòÔô±÷éûˆ5–a f}^š‹ . ² ò ç øfÖþÃ÷Nóññí]í ï‰òÌôNù©þ3¥ª ç {sd§ Þ „Krÿ'ºÿ¬þaýÇùåôbòÈñæðàñ ôí÷ÑûmQ4úëCòp)¶R¿ù¶ ý š  x÷ÿ®ù–ó™ðhì‰ê©ë|ïˆòæöªü€Ÿè “ › n á ’éÑ¢6.ûÿ1þ ý-úeõòYñNðÃð‹òNöþù_ÿsœæíâ’ÉRzCà„ "Hà µ ûiJûSôñbí¢êúê³í¤ð ô ú×ÿh ~ u¯È)¨ ^ #Déÿ8ÿ€(hþ@ýoúƒõâð·ïîÁîIðèó÷ûˆTÿÆÿÒþŒ»á^fò¨Œ ºŠe6 GÆ&þúõBñµíVê¸êcílñ õpúi”² ]Sÿ®LÒ\ l LÍÅÿYþiýü¾ø#ôñÜðXïlð™ò®öÄú’¯»þ»þãÿGÿcÿ‘þx<à_ú 5—‘$ ~MÂÿ—ø¸òòî;êsèàè©ë ïåó@ú}N  _˜lÌ‚ š ÷{?¾ ÿëý2ûÜöóeòSñèñöóñö=û ÊÓìªeüºÿÉ Ò ñ Š » Ç º\ÒûÅôYñ&íøêFëíJðŒó(øÞüp°Ð — $d ןÈ3wš¨é‚ÿ“ý?ùŸôäò¬ñ3ñò…ôØ÷ëûô†аÁÿÐ…M@ý© ^ ¨ì$ y Ot þ«÷óóññí#î%ðQóÁönûnܤ£ À G ù•µ Ë âlèþKý'þ¿ÿâþøýDý úÒô”ñ­ðSï>ðgòtöoúÿG”Ä7ÿçþé:kx²œš ò — ¥»LÿùbóÄðCíaìÕíæð9ô'øåüaôi À ð ÷Öž® è _®ñ²ÿ*ÿ5.ÿý9ü{ú©ö>óó¯òáò2ôW÷:ûÓÿ{â)äSÿÆwÅ»ƒ¤Ç ( ¢ Q Xñ>µûôbñíí“ëBìËîhòzö[û!ßwj ! fôW ?X+øýáüxþÞþèüÇûfú„öªñäïíïðÂñÚôbùÝý ‰:~ƒMkÈ#ªË¬ä  i ü ¶ZÁ@ývöáñKïòëüëîwñõ¹ùåþå× ô ÑXï(å Ó ‡–ÿfýLýûý9ü½útúÞ÷cóðòï\ïàïJñ>õú°ÿhÔeq‹Ïèu¬¥]! ] 6‚Ü „ ͵eþùÖò"ðˆì/ë ìÌî€ò&÷üÊ] ¶ Ìðˆ}‰_ / 9–=ÿ&þ&ÿþfûú¤÷øò{îÈí*î­î™ð±ó¸ø—ýرCŸZQΦ‘g›x ' ÿ²Äþ…úŠóÁï‰ìáéxêõìŸðÓô´ù|þ}÷ê é g–?.Ö7 Í “àé‚Ã.ÿ8ýÜûÞ÷kòï¨î“í"îCðûô—ú$rЬö“ž¶ K  OÁ F ¾ãòÿáüÖöMñîéêééÛêÝí ò'÷JüµúY  ‡Lá‘ i±úÊþéþ šÿWýÍûCùsôãïôîÐîãîÎï‘ò÷rüËwW|ë¯( u MßÞñÊ bÙÏÿûgõò£î ì‘ìNîTñfõ­ùâýÆå y vfŸLu ò‰ÿAý¢ýêýbûµùªø³õ\ñ‡î³î]îkïþðõÛú:Y2¹-ÿÆAúí›å~  ¢ -Þ  ?4»ý•øióØðQî¢íôîòñ“õïùmþ« Ö N.ÒÇW > TFŽðÿ ^ÿŒü–ú&øôfðï&ï…ïðð{óFø)þÙ”¤'aÃ" ±ð,ê ¥ n »ýúwô)ñáî²ìí‰ïüòe÷MüÇÂÙ m —AZ°ž l :ËU'ÿdï0ÿ¤ýUüPùLõKò8ñ˜ð¥ñÌòwöÐûÜ/K%¶ÏO.Û®… ¨ à X  )˜¯ütù‡õVñ…ï–í9í™îñrôùGý:¾t „ßªÝ %Šþ®ûžûcý­ükú1ùç÷úôò»ð=ð¨ðòñZó\ø²þÜ/MçØ&°Îo e ~ V h î ê ÏF¡áýyú õjñ?ïíýímðTó÷×ûºÿa 1 'mOTí# ê®@ÿ&ü£û·ûù«ö{õÈóðtîoîÛî½ðDòöõvû$úÇŽp‰­EOÇi ‹ þ  ð y €ÿçüÃùªöéòñ8ïîxïÐñõúàþoô gmžBkyM 5 rìÝþý¬ý}üôøRöúôùñ3î°ì&íÜínï€ñíöjý ùP$@2‚¯2ž b 7 ; $  Ö ˆ7Ôü®ø*õ2ñöí7íì©ì^ï<òòõû×ÿž Ú5MüÏA•- Ž?Aýüàý9ü­ùSø$÷RóØï£î\îï#ðóuø5þb?Ò?<ÂÐbÚ ç  ² > ç Äy,ÿ§ûk÷ôªïKí•ëöéKëŽíTñ-ö¨ûËê \Ä\ʱôR k „ýcú´ú[ú˜÷(ö6öþó(ñðÕï8ðDñÑòšötûUH”¯Ò¾Áü«L Ü & ë  R ` ¾ 2±{ÿ‹ûÀ÷–óˆï/îéëÖë)íAïAò¶özû‡”| T<>®žbÞ ·Äþ"ýèüÛùÉöŒõôpð`îîí¿íÇî§ðáóiøåýjÍáíKÈ ( ƒ è Ô N ¶ q : 5 g®Qÿeü-ùîöRó+ñï¼í%î¡ïŠòuö\ûÒÿP‰  ¾ª½¼, : yÿýNý’ü^ù&÷Èõ“òPïÝí6íbíOïjñ¬õöúþ¥l›¶û´ f É ?  Œ ® ±«>þLú÷£óŠðÕï@ïÐïPñ>ó)öžú“þóÕ A~é–õ_¼ _ tc½ûÿùõùHø,öèõ¥õóîðãï÷ï4ñóxõ&úùÿ‘Á»*¥ódco ! b ˜ ¾ ˜À„þû+ø¨õŠòïï=îíYî}ðó÷ùüÔ=° N §ªÂŽ v…%þéúûù…ù'÷õRôÎòÇð°ï{ïÍðŠòiô ÷5üºÍ«óh@1²ñ    ¬ × ŒÌþû ùëöbõÑó£ò‡ñTðÂñMóöCúëÿ"Û® ‡y tšÄ {¸}ûø÷-÷põ¨óóªòµðîEî­ð\ólõÍø®þ…- V 2 ©d= N ¨ X A R f a{ÿðúìöõôPóòJò•ñéðdðòõMø†üb·ó Ä 0 qü¢ Y~Žþâù|öõÛô9ôxò¡ñ¨ñ'ðîìì–îkñ‡óq÷zýJ‡Ñ  { ;W®òÁÄ 0 r W ¥ áW±þ‡úE÷¬ôó\óPózóòñûð<ôÄømý¶~£ 'q)2ø†Y[å á“ÿû÷õøó[ôdôcó$óÕò9ñoîdîîñyô¾õ¯ú‚{5 ñ  t ÿ» ' ¿ ü º ºèÔvûáöâôAó\ò[ó•ôEõ”ôŽóÄòNóøýOC *¥¥‰UÊ¡ Ê>_ý„ùöôüòhóóYòèòòñïèìwï¡ó¤õ6ùŸÿ^À+ ¼ Í ¤·Hµ … ¤ P ß ²½ñÿwú*õÁò«ñïð(òŠôö´öØõöœõ{øþüÛ\ sµ/¼hE¼õ\Vÿ\üVùöôåóõuö·õ+öðõ=óiïÃî¶ñîòñõ¼ûXTÆ  °Ž - ½ ‰. Õ jOëû<õøñ¨ðQðåðòõ/ö¾öøÌ÷€ùÝþ÷ð ÖÖ«4ñõ; ÛÛÿ²û’÷(ôñò¦òDóTöã÷Wø(ù×÷ˆô¾ñðò×ôýö•úÅÿ ã  *Å­ # K m e ù(aÿÔûlõÙñÿðžðñ²òõ*ö{öø=øcù‚þ¸vÓ { ü ePΊŠd¹ýUøEôƒòòò¡ô ÷#øPùAùJ÷NôõköÒø‡ûÔ  9 S °r™ yu7} ­þxüÌ÷õÒôÄóô2õãöb÷/÷ßøœøßø8ý/' e H®ÁŒ2ëê SAÿüø ôNóýò5ó”õwö0÷Ù÷øöÕólõóö‡ùMüéûh Ê ø « Ž y/5TÎ2ÿ1ý±ú¡÷˜öNö¡õžö²÷£ùTùâøäúúíúÍþò'¨• k ‡NyÆ €6ýëùYõŽñBòTògôV÷ øâø˜ø°øòõ õ±ö—øsûÿ'¦ ˆJ S G¡‹¦"¤vøýaüMúÿ÷ÆöEõ õìõÒöùÖ÷ôøûzújüÿÍàY “ º ŒŠcxq¿ýú ô?ñ}ñ5ñ€ô(öø!ù|ùzøåõ¬ö¿öðø9ûkH lˆ ƒ $ ‚ |bà Ëþ¹ý½ü,ü,û¿ù¼÷è÷2÷9øù÷cößørùúÐü £Æ Ò p4[ß1w *%«ü®÷%òñ`ð òNôþôc÷qø~ø‚ö6÷6ø'ù†ûjÿ£È nà r Ö ³ qFuaèþHýNüü=ü¦úúørøøÊ÷øöøö|øøCúíýè5µ0  ñ99e3 ûBÿ(ûPõµòYñò&ôçó6õ‹öõõÉóýó²õvöµøýÉÿg S ì ¶ ­  ÙÑíúwfÿbþkþuÿ^þ©üQû_úÑøÌù§ö@ö‡÷Š÷Ôø üìþ±Ž‰ÿ „î;(ß <q‡ýÃ÷Ïóòðñ#óçòFôqöEöÂóàóÂô®ôöúþoèE Ü q Ø X ]/VVÏI–ÿ#iMþÊû±øøøæõ~ô•õÎõ÷æùÖü ÿÉòÛ   W VÛ% JÃüÑ÷Ïò7ò•òñðñ%óó4ñ½òëô‘õ¢÷ŒûµþÂ9î ö p  ë { #`7êÿ­þ]þ³ý(j—‚Vüû]öôSô¹óMõføFûþDUôz ½ w £ ½_ Æ Ï&¢ÿòúËõãô´ó±ñ˜ñãòiñŽï‰ð¼òºóýöÝúÿÕüÜ ì ‰ Í h›]ÿIþ^ýJýøüši kèÅý¬û.÷ìõIõ«ô3öªø¥úBýÒÿwò£• º Õ ™ œ ì ‘ -±­Óû…ø¥÷­õ%ôpôûóDñðÖðuòô‡÷×ú,þTh×ç ž T ½ éÝ«ÿýKûöúpúüüY.С”¡÷ý]ù õåódóòó÷öcúý&¡b´ñ: Ï  ‡ € M v µ6­ÿEû ùµ÷Êõdõ3öôŸñrðñ—òrõ¾ùòü o™A Û ÷ \   £Ìþ2üúÃøzøuý¯å í Fñÿ]ùõ`ò€ð…ð0ó‘öyúrþ8É V Ù Ù '  Ö o  „LUþRûùÞö*õ3ösõóñÐïêðsò+ö·ùý¢Ü¿Ù e § â   ¤ÿÜü—ù,øÚöØù/õ+ K ¹ÿ*þSùøõ¤óòöòNõÂ÷„û‰ÿè[ó û S J Å è “ ó á ñ£×ý?ûaøösöoö*ôBò!ð‹ïð6óEö‹ù"ýDßæˆ ® y 1½sýPù<÷'ôAö‡ûôº å ˜ ñû“÷'ô‡ñóð+óõø¢ü¹¹™Ê L  ¬ Å g û « ÿþ%ûVøÊ÷øýöÊõ'ó3òÈñ£óòõAøôú¦þû.• ï B § ~ Üÿûk÷/óýó[ø©ýãrû . K 0½ÿüøÕô.ò’ògóxôÒ÷Ïý«ËDÊ  ¿ Í œ % æ ± ŽÿŠFü8øò÷Ò÷ºöcöôòòVôíöDøJúý%ÿÕE ´ Q Ý üÖ8ý/úsõ7öú´þç: Ÿ # »vÔýžúÊöômô¶ô{õò÷yýU‹Üû Ç  n E º4ýpøT÷—ö©öD÷ôõ€õ÷õø¯ùFúÿûŒý?ÿRA  LñcÿTûoøÄó,õ$ùýýÿë° ßuÍý½û.øûõ¡õ õÝó•õ úhýã0%î ! . / Y=ù ] [ü†ùFöJõ‘ôVóƒóˆõRùáû¥ý^cåQd ™ Ð b›çþ+ûðöSòaôøÞüyÿ7;–T+ÿËýsúù§øÝ÷‰öøâúkü<ÿö  Ø ç õ Å ³ ! :s¾þÕûøo÷)õþò7ò¶ô÷Tú“ü¯ÿ*¥Ê   A éÆŽþîúÇõó†õÏøÂü* s¹UºŠþþÚüñúAû¦û@ûÍú#ý7þ"ÿ⬅«êÔq¯ Z - W 8 ÉÿCúN÷¨õÅòÔð—ñ+õÕøÓûXÿmÓáëë † œ ›õ¹ÙýÚù0õÊôÐö©ùCýÕܺ‚-ýãûù{øùú)úwüxÿºq é„IÍIñƒ + \ ÿËBAÿ„û‰ù§öÆókñåñ£óXööùÎýHs –‰mï Â+$þyúUõŽô%öQøðú,ÿpSI e×ýýÃúŽøéø>ùùOùÅû¯üàýÞÿ캩¾·¹¦Ž ž À = ¹Ùúÿ@þZú÷­ótòZóWô÷£ú5þrÙÝ ÀÅŽ  î¿ÿîù$÷‰÷ùAú4ý}#·¦zäþ#þžüõù¿øøù|ùšü™þ¥ÿ­uTž®˜ÄÆÞstnLgƒDývù-ö4ó/óKóôƒöbøÏý¼Ö — rúG OC°ú¾÷ö÷¿ù@ûCþÁ¯OjЉþmý6ýçú¾ú…ú±úúýªþkÿ§cͰ^óº?|JD ©æÂeÿüüùæöAö¤õÎõ¼÷cø|üS6Y o Y ' ]ù9žû<øHølùÈùûsþo<0qÿrýÙüÄùhøð÷wøùKüœþœyE ‚ ¬ Ái¿áËì®ë6r§2]þHüÌùeù]ùÉø_ú•úTþÒæ£ F ­ Òß^ÿ7ûìø’ùãú5û3üªþ2ÿ}5ÿ”þ°û9ú`úß÷B÷b÷æ÷|ø2ûEümýÏÿ† } ˆ H µ Ï Št¶à¦„bþÿõÿ%ÿaý+ûùù¡øpøúbúèý 7 O Mã G G¸ÿ%ûUù–ú«üÝü4þ÷ÿAä>ÿ\þdûÆúwú9ø÷ öFõ»õïø6úGüŸÿ­ú‡ : 1  q Tio²ôïÏKÿ‰ýöú!ù¸ø‚ø.ùÌúžûÓþÕU d ? B ( - þÍù“ø1ú5ü„üþÓÿĪ<ÿÔýŸú3úCúÝ÷BöÐõ5õ"öùÞù§û<þ¿Ki Ê +ó  ‚ ¥J,º zÿ”þýgüúÿøúøø½ù~ú$ýø… (æò v }ÊwüÂø0øÅù’û¹ûþ1ÿÌÊÉÿÓþoû ü^ûŠùí÷ïöàôqõ©öÔö¿øûOÿÃ Ì 3 £ s ëÜ #žyUEäþ=üµùpøå÷(øÆù ú°ýþR Áë ê òòâý±ûü‡ýYýõü_ý"ýþ†üüúFùÇúúgùÉøRøX÷¶øNøÜ÷DùeûUÿÏ£ n à Ü—%Z^Æ’üÿ–þÉüéúfùtøúøkù`ú/þ~1  Ž¦Ö ˜ ‚]íþ|þ)ÿ(4ÿmÿÿÿ÷þLü®û;øøµøò÷Ä÷gø¨÷øªùTù…ù¤úÁüŒ¡¬h n 5 [L:›DÙÿÙþYý!ü5ú¹ød÷¦÷÷úmþ¶ <°*p ¦xrÿ\™ ×_g_ÿ»û§ù%÷ ô”õJöØö*øTù"ùÂú%û´úSûÉüŽÿï‘ G / pÀÀrÛñ? þ¤üEûú—ø ø`øø5ûçþ€ó¦ § s y±‹sÿ½ÕÔ°“«Uüúnõüóâó]óXókô0õ†ö7ùþùKûìüyþ´¬ö}  É ¬…p¼©Œ¨óþûüõú°ød÷röý÷Lø<û½þäËž •  ¶ÝÍÿ:ÿâèĘ  ã–`ãþøù)õHôó^ò£òžóqô–öÛ÷Ãø~úwüºÿ„¿7  ñ = /Ðìg‘\ÿhýJû=ù¦öwöö÷û¸¨St ŸAJh‚ýDüþˆ¡ÿ%  [ 4¼ŸþÕø¢öRõ½óŠòÊò{òâóeõönø‘û_ÿ¶¤ ² ìÜ ì 5 ¸î˜|òÊpz¼ÿ!ý;ún÷áõSöOöÛùRþé8{ b éÁÿÂûgø ùìü@¦C¾ ž ê ¼h+þú$ø*öƒóòoñiñ¸ò¨óTõøûÿdU ? Ä´ Þ ¤ GÝÒÿn¹­÷!…ÿ ýwûàø=ø–ö\øÚû …+ÀˆAþjúrùhû;Yz  âÛ×üÀúÃø0öªôµó|ò´òò òºó™ö½ú©¨ ­û ¸ ö k:Ú>©ÿQ‚ª¯Ùÿþ!û¯ùmø`øÏúůÜý=iýžùô÷ù ýj;œ"j Ql þü¶úTøCö™õôóô]óèòzóVõ×÷výßI  m º 9 A¶O_zt EÿgþaýYû†úÑùOùJûÊÿ€1DÔÿûü“ùãö‚÷ÃúQÿÎ`µw³X]`ÿHý¤ûXúøB÷ïõvõ[õEôñôéö'ù(ý–ÙÄ% µ ‚ I ˆd+ð~¿îc<ÿýüµûçú¤ü'ÛpÅ*bç9ýù’öMö˜øý9Î6;kpêþ[üüú¾ùù÷éöõô¼ô5ôô‰öBù$ýŸq Š á¬ÓpYÎñÿqÿ—ýŒü»úÖú¬úý3Äß ñ s p·(ÿþú)÷ñõø÷dügIù\+ÿý üÓû^úÚøo÷ªõ¨ô òîñBó_ö´ú\!R · ‡   ¿Â‚&ÿ†þwì‰}ÿàþ™ýtüWúäùxùûºþƒ L U  ©ÔûW÷Üõ÷ÊúyþÑ<F6,ïÿýËû*ûuú4ù¥øÝö<öŒô\óôUöÝùüÿ¤ yÑp \ M ¼[A þñþˆÿZÿAþÍýÅü–û—ùùîø<ú¶ý7þ ½ ˆ fhý>ø-õõ0ùeý*g~kP¶ðÿü`û¿úeú(ù¶ø–÷èöõùòJò°ó;ö­ûù_z ö œ ­ æ Iž’X«L$ÿÎýÔüûùø7øùäû¤®ª – [ R îpÿŠú}÷·öÕùÓý¥v4a!«ÍýŠûïúíú¸ù£ùmøø³öõ÷ô[öhøÁüR”P Ú R 2 Ë Ú~0 û©07ÃþRýËûú°øøø.ú¤ÿtt  j öÖ ÿYú›öˆõæ÷æûÿ€McŒ~eþ€ü3ûûÙù>ù%øh÷¢ö¾ô]ôzõn÷¯ûg$n  W ™ è I œÿ÷Ñ©…¤;¨þýðúýùùEúwþÝ0† T ‡ <m¢û7ø{öhøüŠþ…x\ß\Jý&û‰úúpùøÆ÷½ö¤õØó^ó—ô1÷Cû - n æ æ 3pˆùÎ1ôöpÖÿ+þÒûûéùËúdþ;ìS ù ¸ #Ýûø€öà÷XüÄÿ÷Q9sŸ4ÿÂüWû´úÁùÉø%ø2÷Xöùóæòóöô®ø?þB£; ¸ Ò f 7 H`¯UJ~±eÇÿÿ,ýÖüÅû4ü¨þÁo ( ÿ gýêøÖö¡÷“ûJþZF4V8å€þ0ü”û˜û’û¿úêù‡øg÷õuó|óëô+øoý/+Œ @ , W ¿ YZŒV Ä­}âÿ ÿšþÿü¶ü/üüüvÿ  5 O œ 0ÿ†ü øÕõöúƒý/ C»øþìûÔú\ú6úCù1ùPø ÷ õBó4ó\ôˆ÷âü†ÙÌ ~ X ( G æóEÕGT1$æþ9þŽýªûäûFü þ¶6: ˜F± Q akþVùóöbö>ú3ý³Ê”÷¶þÍûóú½úûdú(úùøø÷oõKó¶ò–ó±öü÷… = ' ‰ kh#ÿÛÿðe©@ÿ þ5ýþúbúÌù‚úýX¾ ò >S …ý¥û{ø ÷éù3ýìੈ£öJQü»úÐù>ú³ù úƒù«øxö;ôŠóZôçöõûiR1  á ¢ p îÿþAþ}ÿ ¯ÿ¸þÁýý¢úù ùXùjûÚíü © ”9ü•ø|÷ãù~ý‘ÒÈ\Êïÿmülû°ú~ûû-ûíúKú±ø~õ+ôôžõú±ÿ²q B M µ ~,öÿÿyÿ±ÿpÿ‡þþLýÖûÌúHúÛù®úéþf≠¾ û R!ü"ù ø‹ú>þÄ à¿Éµ§ü´úrù<ùïøùùQù¤øÉöÒõöy÷þúvÿ;¹k ’ , [ ´ÚÊÿ›Å‚†ÿ›þñý¦üáûêûü~ýûø {  æ Òäÿ8ûà÷’öhøüÅÿÓÜ0ƒqþ®ünûhûÌúÿù´ùsùÝø…ö–õsõöžú¼ÿö \ M Ò Í¤_¶ÿJeÿ)þý¨û<úú7úÿûrÿý• Y t ß +'üGø°öô÷øûëþÌêßR4Qþóûôú…úFúÃùÕùÊùÖøWöbõàõ]÷@ûˆè à ‘  ^ßë@óÿHÒÿÎþÛý‰üíúÆú!úéû.ÿ , ¬ òý±øÖöT÷õúný#Ëa5çþ„üû…ú·ù›ø€øEøNøŒöãõ×õ…ö™ù§þ@Š¿ ‹ Þ ¯ ÝÞò¢þ•þqþ¼þ6þöýîýîüwû7üÀûýÿ8*   #þùr÷†÷÷ú¡ýOÂ,ŽV2<ÿíüBü"üüóú¸ú¦ùqø¸õ?ôžôåõƒùèþNÀ„ Q 5  ‰ ³„îÿ"ÆÿoÿcþÄýîüü‘úÉúDú üîþÄK Ü Ä ’ ®NÃý:ù÷öÖöDúý„~!1G¾Îÿàü8üýûNüDûãúïù ùöOô.ôßô—÷ûüÆ ! > ‰ @ ÈX(ó’ÔþÈýüÙúø¥øOø¨ùáüJ‚ Á % Ø û\øÍ÷îú©ý;2ö#?¾þ…û÷úaúàúXú´úàúzú—øqöö}ö¯øýOTö Ì N  l å<÷¹ÆÑÕÿêþ#þ(ý±úÉùÄø!ù6û¢Æn  ¼ Ý {^ñü›ùøeú'ýŽW‡æh9ÿûWùiø øù÷ú÷øšø¯÷!öOöÐöHùîýµ²ù l ª p ¢ kûU¡c±­çõÿÈþBý&û‡úïùËù²û©á¨ ) ¯ Q «MSüú`ùÙû€þFæSÁ–Ñÿüæú˜úûˆúøù¹ùûø?÷ÒôUôõE÷6üŸê± Ö e  E l±ÿQ„©ñÿœþŒüû úçø úrý¦×ó ã ‡>CFüùbø…úêþà:|EÓÙü^û„úú×ùÊøCø·÷Ýöôôéô•õ«÷AüÏ_\ M+¥ hËþRþðþ‚ÿ³ÿ^ÿvÿÿðýÞü‚üvûŒüiÿIU, ò  ™ UûÔ÷±öç÷æûÕþNÓÖ©È#¹ýQû<úuúEú]ùAù_øúö:ô óñòôÞ÷DýSœ Å “X6´þÑþ¼þ˜þÄýÝýPýûü*üjü°ûPý-%ç * c  ¼;Oüþøûöbø|ûþsÏÕ_£@;ÿ¦üÒûƒûÁû§úGúÝùÎøöÙôrô#õ+øNýù"` t å  ” s/qX„ß=+þdý ü2û#úŒúíùû–ý!ï4 é ± ྟý@ù‰÷u÷û`ýÊ4Ä…‚…þ…û¹ú!ûûñù³ùùëøö—õ;õ‚õ#øÓü?Íç g @ ¼ ¢ „j>™¡Éíþþ ý ýšûîûØúöûµýZGŽ   ŸTÿ^ûgùùÀû×ý Ô=Üþ?ûàùÛøù ø#øØ÷R÷´õôó&ôjô ÷ ü›ƒZ | k ‹ p é­R:4yCNÚÿÿ0ýyüEûû°ý7* æ * e4ý9ùþ÷Œø»üìÿêéFêŒTÿñû#ûûAûúcùQø´÷ƒõôéó$ôö+ûÁÿù„C ô ´ & Ócbe!fÿâþHþþ§ü½üÁûü»þ}l 5 ½ _–ýùŠ÷’÷8û°þðuùƒ‡×~ÿ@û·ù?ù ú©ù†ùoù ùA÷õÔôáôõölûÆÿ׎' t ¾ ËTMW¡ÿ†ÿúþþþþHýCý#ýþêÿ³ ) l Í ÉK¸þâùC÷8öAùâü238K@FJýû\ùtù#øø?ø±ø`÷úô…ô ô£õúÑþHXª ç x 2 QÂC¸”}Žÿ‘þ.ý¤üñúÆú§úü¥þl¬ .î ô±Zû_øD÷±ù™üÐÿØê‰ªæƒþýOü¬üÓûÕúú ù÷ô4óÐò^ôéøÐý^´œ … ¬ S`ÿT`àyÅÿzþ<ýPûúLùwùüÐÄw  æ ®ýQú'ùšû‡þ W±O"ÿ³ýçüýYüËû3ûú·ø]öÊõoõÌöçúkÿB 6 Z ™ r -êþÿhÿòþ6ÿÜþ=þ†ýAýÇûàúWúú7üY<{  ü ñ öq«û|ø<÷ÑùÜüÿJ2íXÜí0þ~ü÷û§üü¹û–ûÅûdú)÷ öõõcùÿý5 Ï ‰ Y•ö?ðÿ-ÿKÿÿ½þ1þ·ý!üiûDûýû%þ)Ê ° ï ù GKÿ%ú·÷÷[ú¶ý%ŸQáYäv™üæúoúçú¢úkú#úú}ùØöÛõ$õÔõXùÓýô¦‡ É  Q Qßrÿ€ÿ;ÿ(ÿòþþYý‚ü¶úéù8úãúKýY¬ Y_ ÿ »Jÿåù¬öõŽøðûbÿXÞÓ#o‘ ÿý¹ûòûû:û›ûçûOû$ùÍø øùàûÝþŒ®8 ú ë Å ¬PØÊ[æÆÿQÿÚÿ¿ýVû8úmùÀøåø€ûG ” º û Ó¤Õûpø¯ö4øÊúþ±ó&ÓŽþïüÔû—ûú@ùùHùËøö˜ö‚ö®÷ýûÎlåÖ Ü y ] Æ*`á= ™pÿþÊü;úûúüGÿ/¯• 5 M² ‰Mþúð÷÷*ø¹ûøÿ ¡BÊH‹¯þÑüUüIüíû‚ûÜú;úÅ÷õƒóóö\úµÿ—Á  ± ò)d ÿ"ÿÈÿœht2tÿÃüåûzü…þ¯ÿ^–¹ „ ö  Bý^û¦ù7ùÉüî·‹½)þþ;ýƒúUùþùGû©û1þœþyü’ø,õ3ô“ôÚöÞû›,Ÿ ¸£Õ;%Ëý*ü$ûÚûwþ<žØþ¬fáÉ|Ι } Š ­ëmþûtøùÐûðý¹é>+NÙqZýûýú·ú[ûËüýÀúó÷-öCõZõø0ý"tì[ È.å¤ÑÿOþý¶ü&ý0ÿáÿ·ÿòÿ½û¾ÿ®ä¯R t  2²¿àýlüçûƒü®ýXÿ·{¢¬þçûfúÓùFù½ú(üFüÔúÿù²ø5÷‡ö1ørûcþ¶óyüà¹(~†ÿÿ ]4°;;þÿÿÜÿ{šmÑ!}prèa²ÿ]ÿ !‰QÿýAüƒû™ûàü&ýîû~ùSø ÷(ö»öåùDýÍÿuË¿·¿F.,Sl,Tt/žµ¢¡°ˆÿ ÿ[ÿ«ÿ`„.¦€dˆ:øÏZ‡xR¦ýlûúùùõùnû&ý³ý=üDúúø÷+÷°ùþÏ3õŒÿAÿ|þ›þçþE«lz/7RÞëÿ¦ÿ²l؉ÿK¹ý ñ&¢Ø{#ë@þ%ûùÁø±ø7ù´ûý2üûùù™÷ßõQöÎùbýÎ6PþØûEúúÿûÿº© V j g ‡ÚšÿžþBþoÿQÿ´ÿãìú,¯B<+ÐÇã\þ#úƒ÷£öNöøãûIýýåü€ü²ú7ù.ûþÓª þ€ýûYùù÷žøWúLýèØÊe a ¡ s ÞÀæþýâûtúüØþ;„TP¼rjP(þ^ûáùÙ÷³öÁ÷ ø%÷Ÿö©÷Fø‰øáûe8 cÝZþ|ütúú[ú]ûÈýÕƒ–, ? ² ËG6Oþ_û˜úŠüËÿ¯îÖßÏe8½•œýpûýúÊû.ûÞü8ýèú£÷²õXôÐòÁó=ø+ýî|€|Vsßÿþ¬þ¼þsÿŠ7¸!î‡Yè6ÕÚyÿÔü\ü(ýAþ¤ý›þ]¼Å};ÿ~ü$úÚùéø0úvüÇü!ûlùžø¨÷÷\ú%þ¢°oÅèÿ}þŒüíûËûzýÒÿÔöþS° AvÍ8–þÎü/ú6ú¦ü©ÿìÿ)ÿMþýØþÝÿH$;SÿýTûÑúµú\ú“ü‘ýiýsü¾ûÐúÞø]ùZüA¨îóÇEÿoý¡ûˆû=ý6ÿ qž S Ì t [ ±'nèÿYþû˜ú·ûþUþ!þþ²ý‚þXÿúÿ‚4Õÿœý;ú)÷2öˆö¿öù–û#ü>ü"üü ûFûþòèÝ¥\lkåþ¡ýý²ýþSÿé ú ù  …݇„ÛðÿqþTÿ¥¬jWIþÎý|ýÄüìüüü£ûtúù²÷µ÷Nö ÷ÚøþøêøùÔùcúvûûþžØ0Ö%åþ=þtýçþ Km2k“ Ž å›y HXÿðý«üÕý‰—Dh›ü÷ÿ(þ¢ü û¿øvö™ô¦ô6ô õîö÷·ö÷–÷øøœûÎÿûPò:>ѵÿþ$ýõýŠÿj"¨@  i e GzÓý¡Gÿ‹ýþáÿ /©² W¦~ÿ±üRùöôwóó‰õµö•öJöÈõºõõø÷üĂ֯k»­ÿ!þ£ü=ýÿ{³¶» À % ±K äù-ãÿFýnü]ú´ú¨ý¿z¸ð૘Mc•ÿwü¥ùRø"÷ÄõËö÷…öæõöƒö”ö[øñûØÿ¶¾ ËŠÿŸþ¶ý9þ9ÿn› æ T ƒò‘ ý€Z`þkürù¸ø¼úÆýÑÿ(‡ÐNÿñýÁûŠùAøŒ÷öò÷0ùÌøî÷S÷Æöqöp÷aúaþPÏs$ÈÅ’þ‚ümü(ýÅþ#¸Uí Ý » ´ a RÛF@ÿ'ý^ýlÿ½Ñ€æ½›Ø–YʧþVûMøöö2õ6ö*ø\øø®÷O÷Ïöïöù´ýXšMÖÌ*æÿûýýýùþÑs%¦{ r  ’ жO¹ÿþƒü¢ýäÿypð•ß×¥‘ SFýÇùB÷)ö•ôèô&÷—÷Z÷üöÃöröŽö ù ý[ßYÝtVÿ†þøþs ocÆ R \W … ©†8ÿ;ýžû!ú±û‘þ›ý±€3ý•3ù¢ÿýPúwø÷€ööø†øÐ÷³÷B÷‘öÝõ÷dúþ0 ì•ÿ†þÎýÿ¦ÿ}¸ ; n5èS  Uß"âý$û²ûÏýËÿ"æ8Ry-P8R”_þNûù²ø%ø]÷)ù¾ùù’øZøø¸÷øMûôþýUg!ÿü¥úüùûeýįFV I ÿw Ò O®/}ý[ý¿þ£º% ßúwØMíþ–üRù÷äöæööö¨ù¡ûßûûçúãùµø6ùüîÿgæ;B eý"ûðø?øÄù@üFÿ /L ¹ þãû ßkɦúýšýÓþµD(v[<Súòÿ˜ýîùëö‡õõäó·õo÷ øöøüùÑúÈú«ûþý¥¨]…>*þÆühü·ý¶ÿsZ°èÞ E ¹ ø MŸ2ÿpýMýíÿ± v²‚ $¤[ÿWý×ù9÷Ìõµõ®ôö”÷c÷Ý÷|÷£÷d÷³øßû ÝJe.BÓÿþNüÏûQýaýˆ} ¼ ØD ,_Š˜þÿü{ú€ùiû(þèÿl…[)ÜnáþóVÿDûøkö*öPõÿöŽøhøvø¼øù´øïø`ûÿÏíoɪZÿþÐüMý6ÿ›È± % Þ4œ Lì3#vþÌûú+û»ügýØý»þUÿNÚÄïâÝWþçú¥ø˜÷Åõö¤÷r÷^÷2÷³÷à÷[ùOü³èç²mÕþqüËúú,ûNþ©™Ü‡ ´Qš} ¾¤5ˆýîûýóþ÷ÿÓ“õ?'ùnŠO¯þ>üïùøã÷žö¦÷ù]ùÝøêøúøÛø%ù7ûaþ8œö*°ÿsý?üûÚûMýoÿ7Çþæ @ ²W î–CŸ]ÿUüWü=þ?ÿ³ÿ‰s§Ÿ"«ÓÿºüdùÌöföSõörø§ø<ø—øfùÉù’úðü°Â}SJôBþ˜üöûaýQÿ˜Ñøœb\ ± µ"'‚ÿ*ýHþˆdr’vAVã™Þ©ÿœüÛùÅ÷‚÷Yösö¡øù›ø-ø øš÷õ÷ úDý{< NÐa³¼ÿ$þþfÿUNÿÙ ¸ õ í { {õÜÿÁý‹ûü%þtëq|ª`º^zˆý úu÷÷Žö¹ö ùšú/úwú·ú„úÅùTú}üôÿ ÛýÙ¡=ÿ£þþìþñN°°ôª Ø ƒÿ ô ÊŠ ðÿþäû©ûŠý½ÿ'Ïÿ‘ÿÈSÄû/+ÿCýMúX÷”öœõYô]ö¯÷ç÷»øiùúú>ü×þÝè}Î,Þüàû†úûÿüì§N êŠCŽ< I·Xªþ@ûÞúýH!Zü~:lÿèý üÕøNö¬õ™õ'õ„÷ùØøÿøˆùÓùúûµý2[Š6“lUýXüû¹ûuý­ÿu±Ã, ã ^ÿ ˆ ^ï1{Öþžýæþ`²,è}ëâ ëwþÈú4÷õô€ò)ôÑõòõÃö ÷Í÷løGúFýLÿ6ŸÎ'þqüûÔúBüßþ<¶e ² ž ' “ Ã,Å þ¥ý¯ÿY/•‡(dźŠføþüVùö÷f÷”õHöòöžõ,õ6õøõ\öm÷åùðýí¡ø°žÎÌÿDþ“ýUþèÿ« » Í Ô ç ]dÚ"´ÿ²ü’û¦ýŸ¥åÿóqa¸wÆtÐþÃûDù@øfø‹÷Çøýùâø´ø2ø¦÷'÷¥÷„ù¹üÜÿæñuY€ýåüÛüýyÿ}ã>.  F ç ¢whÐíÿOý–ü þFÖÖë ÄwP|þ˜û°ø¨÷d÷öø°ùµùuúÝúÒúŸúEûÏüVÿçøÂyþ|ú2ù]øDùÞû7ÿ à÷ S  ± âL¿åCÿcü†ûGý“ÿ,u7œ[Ü$þoúr÷ö®õqôÉõž÷÷4øWùqúûØüLÿ?è0U´jüúùGù;û)þŽëÔn } äBï )Ž2´ÿlþ;ü*ü þôÍÝ6eK:±§póÿõûæøíöðõ?ô$õ¢öZö\öúöª÷þ÷ƒù/üðÿ²\‡×æêþyüû=úû'ý3ÿ4ãÿ < C Ô ©¡Ü=þîúÍùûñýKdË6D4è A þûmù™øéöW÷†øŠ÷‘÷Û÷Cøhøqù­ûtþ¡ÒÔõ`¿þåüü*ü,ýlÿgy(œÅ˜ ‹ S ÞE!¿ÿ¾û…ù±ùšûlüý²ý=þöÿ¤ÕBX°„ÑÿúüNû•ú¡øëø½úÿùÀù&úXúú’ú'üíþ8øºóèýÙûûúMûý1ÿMoÄã €  û ÷ Níþ&ý¹ý¼ÿkCÿ™þŠÿ`ß{åÿìþ%ü6ùøÛøpø{ùíû©û5ügüÄüAüØüþ€zžÏuvþ‘ûqú ùÈúýCÿÅ8ù¬ Ž ,  † Èž°Ïýâü2þ–¨¡9ŒêZ£˜ÿ¨þ3ü@ùÆ÷X÷ñõöJørø—ùãúü±üFþhþÂijÅ#ÿ ýAüõû‘üžþtr&~Z Õ › ù¾·)©þ¼üúû ý–Áî”0svCÑ3GÿÁý0ûNøìö'÷Zö>÷Žù ù»øÝø+ù%ùUúsü%""<ödIÿûýNý>þ±Â˦¤ Á ± Ä ,™4ÿÒýÙû/úQûÓý1Ãè+*±ÅŒH"ÿü…ø‹ö\ö8õö¸øòøuùú­úRú)ûÀüÿ;­\_€ÜýFýýWþoµ*xJ ˜ ^× Ú Q3ÝFþÇû¨ùNúXüZþÿƒÿ;ÿÅ–Q/D!ü¡ø÷¹ômô˜öÇöx÷óøyú/û}üEþ÷´¿eÀõÊhý[ü‚ûKü¬ýOÿßð„ì 'm¸h p Àˆž…þaûUû ýéþ‹ÿñÿMÿWÿøÿOÿðÿÿþ5ý«úðøiù<ø¾÷òùÌùqù:ùîùòùûýK¤‡Î1מ]þý§üþêÿããâEs^ R v  µ.BäèèÿÜÿ-Ì«ôÿ «ÿ þ¶ü¼ú ø.ö¥öööÚøÀø÷øúùGú¿ùÁú=ýÆÿ±1H!æû´þ•ýBýÂþEZÀMË ? ¥ ´ jûÿQþvü¯ûVý¾4«Y/4nB¨™þ·ûøö„õ%ô7ôi÷'øYøOùÏù#ùúüØþ0Í6Vªÿ§ý¹üpý¹þظ ìýA; z$Fýûeù;ú‚üÞþqs7=7÷uüü­úJùºööÍ÷ž÷E÷œ÷¶÷ìöEøúìüm&Ñ/ÃýpýÈýÁÿ-V30ö  ÒZ P Kgþ€û(û‚ü½ý.þ/ÿ5™é¡Œ¨‹AþÃûÐú¦úù.ùQûÆúšúžú;úÚøúKü‡þ__fÌe¸ýjú[ùŸùÍûìýKzf¸A x¨Êo a +ö<üýuý«þ“ÿsÿôÿŠjïGÚ‚t)ÿ'üJù°÷Ëö4õ{õ[øüøMú©ûKüùûŠý®ÿÛS¡ÿ>»ÿuûðù-ùuújü†þ„‹u ' ñ : ´ ì8^f[ÿÿ¬Ý>Š<6 ŠPÒÿlüLù{÷Möôíóªõ ö•öÉ÷kø+ø;úåükÙ;N±ÿµýÐûoü¯üáýÒÿ=™®  } H ’øÏ‘ÿUK1a<ÁG¸B{ø–ÿýæúžùƒø"öö÷ÇöÄö÷ ÷¢ö…øÌú’ý'I{ìѳþþtýâþ7€ÙwYw ² $ ¬Û Om×þûü°ýiÿR|A6Nª‡˜lÿ*ü£ùsøÆ÷Žö*÷Vù1ùXùFùù”ø‡ùJûtýýîÿàuþüLûÇú9üQþGÜVáÐ G f 8  Ò­Îÿœýü<üŽþÌÆD ݀^ýû²ùcø·öÄöˆøcøËø³ùçùÉùõú üÉþ’ç)þPû5ú‰ù û@ýŽÿK[±z À Á › ²µ¢‹TÿÁÿYþÇVù]¿ä=øÿ ýyúÓø$÷,õ‡õ(÷\÷Dø^ùÑù.ú)ü7þ¦†¾r¢"ý¹úôù ùlúAüÚý@^§Ê g e Ý ë­þiü|û·ü”ÿêwŽY(^$‚ùþlûù¦÷¯öMõöZ÷»öíö÷e÷ÿ÷Þú™ýïJ¬ÉAÚüöúîù û¢ütþLXÌ?y W ß Þ}]εÿfý§ûýû'ý'þSÿ®“>P Ù½¡þ›ûƒùB÷àôƒõpöžõö(öUö€ö³øÀúìýý·7ßgŒÿ…þHý'þiÿ…ÌdÉ0 2 µ VtûãÿØýyüýþFþHÿy ZÀjD‡d*ÿKýäûFú ù.úúHùÒøøòöeöë÷ªùÚü2 nBãý ü3û¢úÍüNÿéUC c Ó 7 V /ÒU!ÿ=ýÜüPþŠÿìÿ‰ç´05v»Y¨ÿªü^ûú1øj÷4ù³ùñù¹ú…ûÈû4ü*þâÿHš* Ýþüú‚ùìø6ù5ûþé·L/ ï @  ; 󜶠þÎûúú;üÅý¢þ)táé¢ç¼<hþµú8ù)ø§öýõÓ÷ã÷¯÷øNøéøÃù€üzÿ¤;B {¡3Hÿ üùgøÕùòûšþÌjjO “ Ý  Þ´u|~ÿýýDþ=ÿ'ÿ#P{Oö ÿûÿøc÷´õ õ×ö'÷D÷%øøxø:ùƒû‘ý¦€~M“ ”ÿôý•üáûý®þÜ@ll º '  .°-¯ÿQýïüñýÁþÅþN¬¢‰Õ!|gYÿ;ûQùy÷}õmõ¥÷øEøÊøVù7ùôù>ü/þ½î<wÌUþÁü¸ûãû}ýÏþ7“'° O ¾ vÔ^%(þðû¼ûÌýÎþ#ÿn–oô ´SÓ!­üû!ù”öäõ6÷~öÉöŽ÷Cø¨ø…ú¢ý$‘†¶[—èüûú—ú½ü6ÿgþ Y 7 C  ©a8«ÿ ý‚ýæþüþÜþH¹3µ} gþ ûú·ø¼ö ÷]øH÷‚÷Ø÷øGø'úýÀÿœ ^M¨þ‰üáúoúNüþžZ7 ‹ ² ¿ 0 AMi=ÿ0ý'üdýØÿ;jðƒ™òP$Lü7ù8ø>öAô–õ9÷¸ö}÷QøŒøùûúŠý“úÊûVR˜ÿzþýgýÿÅ'Ü– \ C  < ÌKÞýü)ûýÞþ1ÿCd»[>áKâ]çýìúùÞõãòÂóôCóôáõ÷|øzû.þš-UéÉgÿÊü<ü†ûÜüÇþZ8`ì  ¥ ˜ ˜c‚ þÁûûXýâþ,ÿ,„¹«n…ã»(/ý¦ûÖú–ø÷ø,÷¼õ¬õhõxõæöêù ý¶ÿ[Dù±ýéû´ûbû¦ü2ÿ`mù Ò ²ŽÍ L h n’°þ]üü«ýÃýýïþŒêÛ·P|üóúùðõ*õYö¨õ!ö ÷|÷î÷ úÓüºÿÕµ˜lüÿuüoúEù1ùòúmýXò^Ž Í Ô2$ « ý6’ÿåýþŽ¹Ç®éSW*ú\`hþ©ûëú ùAöö[ö}ôôNôØôfö±ù5ýoF]®FM-ý<ûèù3úšûœý%ÿ¹1õ\ K µ m  I»ý,þ{üVýpÿ¬ÿ¯¾3Ñ‘¥iå¹ ü)ú>ù£÷áõ°öèöƒõÃõªõRõìõÎøüˆîö aÂd¨þþ"ýþÝÿ¤3   Ì j(‹]Aÿ$ýîüßþƒì÷!uêARI=>ÏÿïûSú#ùëö‹õVösõ’ôïô]õÔõ7÷{úWýⒺɎí9ý«ûfû€û4þ™d—u _ vçâ Ì CêHþ¸û…ûMýþÿ³kpÛ]¢V×ÔÿÀûúñ÷Áôáó„ôŽóŠó1ôÒôóõËø©üQ©ží&ÿSûéùùMùVûþýñ­r ¶_ñ h ¿ÅÓ€þ’ü ýÌþÿðÿj‘Àmð±ß)žÿAýÚü­úÉ÷v÷êö™ô óêò‘ò–óÕöÐú°ÿÞÆžb=ÍKýqû ú”úœü¬þl˜” þ @ é § åöVÿ&ýMþ‘ÿéÿš6œhð¿R$G<üúù ÷ög÷A÷öõªõ>õÑôpõÌ÷øúŒÿSq¯"KÝÿ þAýüeýÒþŠ»0;´ Š Ñ Y * ¹¤Ú,ÿâü üúýJþ÷þÝÛë^Ò5X¥Mýžûýùÿößõ'öðôãóûó1ôôÍöú¿ý2õ!ýZ¯ÿäûwú>úû ýÓu•w ' ¼d: a–Âÿšüû¤ûéýþý+ÿ Ì‘S̶9@ þëü¤úå÷¥÷‡÷Âõâôµô]ôµô÷súkþ¬:ͳÂÿÉûYúPùxú©üÎÿ 3ž ó —rþ  ¦mÿqýiû^ýþYþÒÿ­é.ËÿeÿBÿŠÿÿ€ü,ûûAùá÷òø*øköömõûôö*ù©ü,éÏfçµüÁùŠøö÷Uùñûñþ QÏy2  ~ÐÿAýÌü¦þFþüþ°–I‘Ÿ\`7þâùáøO÷tô‘ôÝõ•ôôgô!ôæôl÷ û¤ÿ5v^µ¢=SýcûfùKù‡ú»ü“þÜ r w ¼ þ œ Où®þÒüÒýmÿ*ÿ$&’'› /àÜþ.üûømõ‡õÿôuó3ó‰óØòBôh÷û^M Pìtýÿíü[ûèúùûþª® Ž á Ú É { ì‘dÿ–ý`ü¦ü­þÿlÿ‰o2Ö¶ËIPÈý¼üuû øïö^öô©ò}ò½ñtñ_ôiø1ý_$‘ñú/ýûÔù.úŸû£þa,| ¡ #äjÈ Æ i‘þ4ûåùû­üÁüSþ¦d»>¸wÿÖýIýNúødøw÷õÇôJô¦òóçõnùžþ)¦þ‘Kÿáû÷ù|ù÷ùðûÿ¼¬Ñ { ¶r l Ë ñþ´ûúûxûºûLý[·`d¿¾„ý­üŒû\øª÷Eø*÷uööùõúô‚ö"ù°üû.‹€(Zýûú û ü¼þS@ B Ë e { o þ ž›ÿôüû4ü ý€ýZþuExÏF»ÜÌ›-þü•û’ø™õ–õõ˜ó¿ó`ôNô~õçø®ü4/dBœß¢þqû$ú¤ù~úÖûŠþã[í ›)þÏ € ôOXÿülú–ùªú”úõû®ý“¸¦¬œ1ªžþÇý"üø®öÿõpóšñPñÓð¿ð]ó÷¶üâ: ! žÏþ[ü†úaúIûPý_× )Hã­ ß L èt?ÿ ýûÐûûû%û°ýéÿN¤àHí›§œÿ)ÿDÿ·üMúú£øBöõ2ôHóÂóiöžù þ¨×ÒÛÇRþ6üGû^û–ü\þõÿTP S zaC h ˜Þ½*þ]ûNûüúúÚúŒü¥‚¾I¸[qaýzûÛû ûÑøù—øeö”õ\õõùõœø<üÈ7P¬¯›ý úgøí÷dù±ûgþgV ú—ëè á ½ ­7íþ”ýýÿûŒûÆûÿ&$β—24ýòü£û¢ø8÷OötóÄñxñ‰ñ”òñõiúuÿOªQ §¥Üdþƒû•ù²ùÊú­üßÿ:" Ð èñ ° ½ ?"Ýÿ|þuýuýFüâûˆûAþ)é ‡¶¬`©þ…ý¿üÑùÿ÷øèõœóaòñ%ðÆñœõúQÿŒþTÈÑ)Ðÿ!þµý®ýMÿFH“ êeY01  ¿Œ@þBýmünýºü0ülûñüX¢?Ût³æ§Xÿÿ’üýùù–÷pôtòGñ\ðÐñ=õšùõýÞKÕÏjþ³ü(û1ü‘ýÝÿMcc ç3 Š m ̹Èþ5ý*ýjû‰úßø»ùêüÿ¿ÿ è©¤\ýƒÿÉülüèúl÷IõoóÐñZñ*ô&øFýlYÄQÎþ)ü ú{úÉûXý1ÿb YôÖÖ„_ Â24ÚÿçÿþùüÌúRú<ü±ýEþkÿsr:»þ ýÐýý­û ü°û}ù¥÷ßõTôäóâõÇùAþ%Øë߸þRûòøÞøîùäû5þ¿[ ?ÇÓM‡ ô“å‰16‘ÿ'þYýùþÔÿÙÿÒ³¿ÕÿZþAþèü’úÞùüøÄöõô•ócò­òLõvù±þ÷I©àgÿ üpù*ù'úüëýß0é ÷ÍD • ë «n}–ÿòýÿüÅûpû»ý·ÿœða·lRþ›þýHû‡ûû¢øCöÖó…ñJðòzö‡ûªÔx6˜bþ.û7úùú§üÿ+» ú-T’G ñ ˆ):˜ÿTqþÀýèûòúÔü9þ;þÿîÿqéH¬ÿ¹þü ü‘û=ù÷õó ñ%ójöƒú0ÿÒÃT0øÿ^üóøeøXù5ûÌý¥¢ /âIK@w A òúwΑnÿý¥ûýOþ¼þzÿáÿ£ÿ¨ÿsêþüýxþæüÿú7ûûùÈ÷ö5ôóåôøÕülƒh½QŸýù’÷`÷Ýøüóg1E£»¢ p cÁ€ÖãÔeÿ¼ü?ûýKþ ÿ®æ”ÿÅÿ§ýêü1þ×üûÈûõûúxøûõóò ñlò’õâù–þ3e[çLMÿ¤ûíùùDúý¸H S‡×—m£ IMÿÏtžêýküÀýûþÿÌ*Ä|þlýþƒüjúÉú&úiø÷öµô™óÒôÎ÷Kûëþ‹‚‹||þûûùfùèù—úHýä 0Ù£HÆ / ;Hcÿ#üÔú´ûvü:ýÿlŒ-Œþ0þ¨þbý(ü–üLû{ù`øvöÌôô öùü¤cå|v þVû™ønø‹ø¾øÔû¬»Yªûè¾x ¦”hw.âÕËýküøüXýYýFþ¼þ¯þÿþÏþ<ü§ûbü û@úXûËú:ùNøñöTõõ§÷kúŒýø—½0;¿7ý_ùù2ùùRýþ¾ ­× ¯!  ’;ÛlKçiš ÿÇþ[þQþ8þUþ­þôþ¢þÓûvû”ú]ø’÷yøý÷Ö÷Àöæõör÷'ùüšožr³uþ#ûAù¸ùnüWÿ.Á TXH  ­HÈk·úþˆü¸ü†ýuýŽþÒÿÔyÁ±Ñþ{ýGúnö¿õ“õ1ôºóÝóôôfõ½ø&ýÇoö Y‘þzûøÉø ü*¬¨ {>ÐîF® ¡P‘Q.í r“ÿþü9û/ûnûðû‹ü©ý6ýþßþWýDûtúÎù¶÷ö:ö'÷ãö'÷Røú”üjýÑüüƒûÚúTøsõö!ùžþV- <ýr  Ç*äoßÔÄÅÀÝ)<þý»üAý„ýÞýýkýåüwúŸøwørø÷ö÷Kø3ø)ùyûbýÿÝþþý#ýÝüjü7úu÷÷OùHþ21? Ù ¦ 2 îÓø÷Uð:³…ßÿsÿ+ÿaÿ2ÿ þ)ÿ§þÍû ùHøÊ÷7öJõ¯öã÷Â÷(ø…øžùÀúùú?úìùÖú>ûKú·ùÑú¿ýS_Z À /ï ë¨Ç«‘àBñöÈp6@+’RÍ«ÿ_ÿ~ü«úÃúú)ø!÷°øSú]úûûû úyø ÷VöÿöÓ÷üö,øú½ÿýeE ÝHz ò bêV¼ø˜xËïA+ªÿ¨þ þÁýÓýÉýKýWþäý€û_úšúÞùÂ÷±öá÷¤øŒùûJü‚ý×ýŽüšúDùÎø÷¢õìö0ú<` x žh” ^ ÎŒqÑ:X'åo©|5¯!MóîÊÿ(ÿFÿ üÍø‰÷,÷ö¿ô|õ(÷cøTú€û›ü^ýjýÅûWúOù>øÖõmõöœú"ÿ´] ò½# õ`{ƆÇʵ2fÏZ¹Ùÿzÿ/ÿ‘ÿ·B¢}ÿýÇû_úÚ÷žö÷÷þøÞù ú“úCúwøÇö%öùöö[öu÷ËúøþjÓ ö k J  $'Å©ŸUu3â+ Ež bJv§þ½üuüÔû¬ùü÷øÒ÷ùÉú¼û˜ü}ü_úÆ÷5öbö-ö:ö—÷ú%ÿUC*5 y ÈZë£þ5³ oQðÞ ÎðÕ°QÅ6¼µÿ‘ÿšÿDþüÁúÛøøƒøøUø…ø øúõõwõ2ö†öØ÷Œúÿ;ž b Ç ³ +ìæG”pmIJ×F ÿí·›l2J ŠþRÿ“ôé»´ÿ¿þþþ±ýßûÄù6÷ZóŸð=ð%ñkòÜô‘øµý2µD  € VÁN/CÔÆê73"zRÉþµþ¹ÿXN}_Ûý_ý^þ´þŠþïþ"ÿ8ÿÎ÷*³þÊûp÷3ómñððñmó¶ö—üéÿ¥'  z ­uòþ­ÿ,ÿ âw·Å¿ý©Ä:ÅŒbÕÛªþ þìþ×þþ*þsþTþòÿ_ÍIÿ#ûö}óöòDòäó‹ö ü  ¸ 2 ° ïðúÿ\ ÿçÒ&ê#jÆåÿ ÿCÿ<ÿÈÿÒ„Èf#‘ÿ‰þ¸ÿtdÀÒÍÿ‰Bä±ÿný­ù.õmò ò™ñ[ó|öü^W¡ 5 q ñÿÈÿ¢hÖ cWLÄAI…ÿ$þ‚þ¨ÿÿ" LþŸý ÿÿ.ÿÿ CLµ4sÊüøÉôôçò«óöÄúÉþ@ Q 0  (ä¶ÿÛýâýIý^ÿÊÔ W¦”-þâ5„¾šŸý’ü‹ý þâþÓþaÿ÷þ ÿ”DüØÿËü3øõ ô7ó ôTöéûv‰¯ ® ¥ × ‚þþdü:ýáþoÕ¦ã‰þ˜Ô¶\n‡ þ’ümýóþ`ÿ×ÿ\ÐmMGTþuûÒö\óàòò_ó6õÁúNÿ*'¼ Ä á S¬¥LÿÇÿ[þÿʉ®²ï«¥<Þs†ç´‚›|‘þ”üÁüþýXþÿ…ÿ‡ÿaΒΊtþfùÊôaó€ñ òúóùªý%úw  | H„;óþÿÝýÝþw´AmoéÕh›»†û×C²ýˆýAþñý\þ¶þÏþ–ÿ&†A»ÿ ýbøUôqóKòó*õ‘úÿ—ì9 9 ^ Pý9ÿiý{ý-ülýtÿË9è”*HLƒéÿL*òBsvÿrÿãÄ ÿ²ÒH¬¯Œý]øEó”ñ*ðxñÁó§ùþð«¬ Ö : X3P>þþUü`ýÃþÐT¼A µ…`ÁÙ(¢qþãüšý*ÿÿ\,ÏhÁðeÙéþlúÎõúó2ò©òLôµù[þ‘îK Ü  ¤‚ÿ)ý8ý>üXþàÿA91&çŽ[F³ûØE÷_øíýrûÒû*ýÓý«þÉÿçø—J¢þkùÿôfó*ò&ó>õlûHÿ[=Û É o Ø´è}þ¶ýßû‡ý…þä~ò`†wAxDš¤ ɼþ2ýêý`ÿ”ÿóÿ›BÉR³1«þçù†õ÷óò>ó[õû ÿ¡}* 4 a ÿþ ÿþÜýüaþfÿ-µv5Ëhø[;ªYßÿÿ›þ”üRû]üþfþÎþOÿ¯ÿ üjU8êþúú÷±öãõ|öZø‘ý÷ÃÚÁ ´ ­ ŸËþýUü÷ú ýþÓMƒÔ:œLüoäl¨ÿ’ý ü,ý‡þ"ÿÈÿæÿ&ñ½7ÿ-ü³÷‰óªò“òøó9÷ºý¨å¿ Ãf…y Yþ¤üúhûüÿd C– ý+&Å&CƒŸÿýGü6ý#þpþaÿrü®À°§0mü÷¬ò‹ð"ðìðØôñú}ÿ1 %€Á ¶†&Wÿßý`ü7ýïý µ¥·Íãñ£å#™dUÏþÛý;ÿ’ÿÂÿ ÊÍiX‘ˆü*÷¹óàñ`ñ;ò*öŒûžÿ<‰ ç 9 [y¬ÿÏþýÓü~ýpþù½áÿñÿ½y;«5 wÚý7üâýÞþ)y¾Ôc0>°µü÷4óññÖò¦÷»üªOb ; ‰8ÿ’þ(ý ýÐýÿ˜k³Š(sÿ­þãþ0ÿÖÿ3žbÿYý·üwþVÿìvèˆv¹ÿû'õ ò1ðrð)ò>÷ÿüôÓÛ õ w ) ‰P,ÿMþØüŽüµýÌþMÚb®–%QôÈ´+¦®/þübüþbÿ,5bê6ÓÚCýøOõ5óµòóóòøãý±#0 &f  ÓûNþäü¯ú{ú`ûýX™¼l|-Æ«) ‰—ÿÏü`ú‚ú"ý1þÍÿ¸1 SA=˜'EûùõxóÖñÖññò³÷;üU½1  G ¨ MøRH•þæýÂý×þ“ºÿ%3áþ4ÿÝÿ2üÑ *ÿ‰üôûnýÈý‹þÙÿŒèk —£ëüÎ÷5õœò7òóVø›üæ› “ „ Í ü]áÿ†ÿËý„þ0ÿò B­`鼘ÀKãÙȾHÿ¯üŒú¨úEýöý³þjÿDouáÃc"üùö¾ôÃòWóbô°ùhý,/Æ .¹ º @ðþ¸þÚü°ýQþËÄX ±“=°lµ¢ôÿÈý(ý+þÃýµþæÿ¯öq»íþ¶ùÌô€òñvñ›ó ùÜü¿ÿ· @ # ¢´Š×vþ-ÿ^ÿºÂ+ÿB×¹ÙN+x¹kÿ&ýßúüBþ„ÿôenäL@¢/BÿpùYôËñvð¢ð7ó™øØû>/a Z ‘ ÖGÿ%þþæüþþâ´¥QÝiU¶èÊ—¯ûï˜þ^ûüfýgþ—ÿGgJ¦,½­—ÿéùöLó]òAòrõ#ú&þ“Áo =ÿmýûÆúHû?üpÿ»ÿÙhí¶úáw-G† ÀýúúüìüJþ-Ònµ[ŠÃÀþšøßôò2ñtñÛõÁùÛý™;< } z ­z±}ÿÑý!ý.ý¯ýâÿrÿo¯TÿÿÕÿùÿkžX›)<öþdýàþMÿBXùÍsò•rnýA÷ôjñ1ñgò’÷)ü,p• D 8 €mËþþüÛûüýöÿ¦ÿ?«—nÿàÿ¯º?´ áýÐü`þ¯þRÿª{&ÇzlD.þ,ø\ôŠñuð5ñpöúéÿëÖ | ˆ à]¿ÿâþ¾ü¿ü‹üFþLÿtþîþ[ÿ™ÿþý~þ#ÿrÿÑÂe‚Qÿ´üüjþGÿ¸‚N‘åê-Ç<ýâ÷1ôÃò&ò”ó”ø~ûà  ° Ùfµ1ÿ.þ'üÍüÐü§ÿ§h|ËûÚþàþçþ¤þýÿ)ül?ÿKýÖú û üjý÷þ=£Î°j¿gü_÷#ôØò¥ògõçùKýù#t P ) ¹5Ìþôý-ýßý þw¶&ǘªÿvþ,ÿÿuÿξ²NžþzûÌû¢ü;ýGþH_­¡«zwû,÷ôtóóÎö0ûgÿ6ì Ÿ z #—ÎÿÔþšýýþˆþØ«ÿÐÿÓÿåÿ‘þÝý½þÿžÿq@ëKXÿáüûXüCý%þžÿ‚dzmÃÿuú‚ö¸ó×òdòšö#útþG“’ ‰ P šëÄlÿkýþüìü!þqãÿûí;Í›Qy<ü÷ñŒþ¼ûÚùcûçûOýJÿöHWP=i=ÿñùPö!ôâóÚô«ù¥üÇoc[ ‚ 5™D5þÔýQüÑüªü™þ†ÿÿ"ÿfÿaÿþ>þþþ3ÿÍS}</Û˜ýYüXýý^þ¿ÿ•ä-‘¦Åý„øpõjôZôïõòúþˆ¥ c 4 싌þØý¢ü^ýuý›ÿÏÿþþ4ÿ"ÿ^þ…üuüÇü ýÿÄÙˆÿýVýRþ·þ¢ÿ(vê$%¢ú8þRùsõó†òúóXø ûæ¿ Ž ô wîòÿ‚þÆü%ýêü8ÿHÿ‡ÿþÿ^‚ÿOþgþâýœý¯ÿ»íß~ÿý¹ú û–üˆýýþY’|Ç–xý!øðô ô˜ó"÷.û"ÿJý† . Ü#ÿþâü>üËü–ýËÿŒÿF–ÿèþSþ)þ‚ˆkpñþ£ü³ú6üÔü­ýÿ_eÝQéu¿Uûb÷Ïôªôôåøü{R^¤ " ÛÿÿRý*ýLýˆþÿˆÿøÿ¼þ‚þüþÝþsÿjZgþ«û~ú0üŠü›ýÌþ+8i'ê>éû›÷EõAônô‘øâúùÿzQ! ô ÓvØWkÿ€ý§ýÒýÕÿ¹Áÿ“Dþþ þÿýÇÿÓf¶þªûýúßû?ü´ýdÿ½Óxx4¿þeú÷¶ö<öøúú•ýߪÀ ’ u •mÿqþÑüUü£ü|ý$3¨̤ÿ[ÿØþ*þo¦5Îþøü ûoümýnþˆÿ:ý˜céÿçwEû×öô¤ôõÔù“üRÃ£ß a [ •œG{ÿ/ýmü˜ûöüóþƒþÿÃÿpmÿ0ÿsÿüþŽÿÜÞ–þhû­ù:û§û¬ýªÿ¦þŒ$W9Mûõö¹õ5õGö0ú‹üJV@ µ w t¿C<ÿþcþ)þƒ WÿWÿ¡ÿ%ÿþ;þ¡þ%þp²”'²þ1û-ú‡úàúÑü*ÿ›Œ×öƒ”ýZøô{ôèô ùTü4_^ ò ¯@ƒÿËþýÁü‘üNýwÿÿ ÿìÿ—ÿ+þýxýwýÿý_+Èkåðýlûøû—ûŒüëý¹å±ÛÞ¹Wdü.ø¯õoõ¼õñù¼û€ÎÉ _ n¡ ‚˜ÿvý„ý ý~ÿuUÿŽÿ0kÿ3þòýÌýÔüÌýèEzJÁþüTûßûüôý@ê ›j Ìý½ù’ö&öžöcùàü²ÿš# 1 Gè˜ÿÉþíü{üüûÚü ÿÿ¼þ@ ÷þåþŸþîý33€Óýû£û‹ûfüãýPu'û¸{*Ÿ÷û£÷ õßõK÷|ûˆþ¤' è ¸ /¤äŠÿTþýòüü™ýþýôü¬ýXý üNüPýgýÿh­ãXýVûJû˜úÞûêýİâ*áÇ;ÿEú‘öö%öEùŽü`¢•} [  œí¹üÿý$ýüŽüõþLÿjþ ÿ‡ÿëý,ü¼ûmûÆúÊýc“¤-Hÿ†ü^üüûFüTýÁÿÁ.”µ°Q޾ýœùõ÷9ø/úþo(Ú  ` Óçÿ ÿþjýªýEý<ÿrØÿ€ÿ8ÿgý±ü¬üœû]ü‰ÿ‰ÿ)ÿÊüüÍü£ü“ýÓþˆÙ»Âk×ýÏøÖõ$öh÷(üKÿß„· {¢ ` ê¥]®ÿ2ýý‹ûü!þ…þ•þ(ÿµÿ£ýšü´üçüÂü)‡*Š6¨ýŠûÍûOûûûwýL¨Óù9"{2û£öîõÉõ–ømüæÿ„ÀŠ  76µ3ÉþÃýQý(ýÿcÔÿ¶ÿLNÿ8ýqüaüoûÕüJÿÆþñÿÉÿÉýYýý_üýÀþ)ºÐ)3Ýp'þÞøÄõuõxöBûþ>Ñ  óÖ·ÿºþhü†ü‹ûÜüþŒþqþ‘ÿ)¼þìý"þ.þbþ¦Ó„¯ŠtþËü\ýÙüMýPþ8|̾¶Õ‚¿;üÐøÉøuøûZþ‚»[ Ž 3 : ¯2fþþðü ý÷üaýFòÊÿäýmûpú<ú}ù‡ûþóý˜ÿci³þïþžþxþÿÈæ¬ðýA'Œ’üøö÷æø þ…~ ÿ ‘R P)TþÇüØúûúYüŠþBþxþ°ÿÔþþ þ­ý÷ý½WÿVÿ(þ_üûüâû©ü{þÌ®öl¨MÞYüâøùÊùŒýßUô· ª% ¹ötþFýûûtúÞúðürýTýoþRÿCþý ýý†üÜþlOÿàÿ ÿ…þóü›ý–ýÙýðþÈ`ûB>wÿòúçö*ö]÷2úÜþ€1Ë 05&n ®°©ÿÇýßû•û”ú%üïü8üJüPýþü”ûvû¹ûû°ü.öÿ) ÿýý§ýVý°ýBÿCV;KÀf¯ÿ×úð÷ªø‘ù.þy / ¤Pf Lj4þ‘ýgûïû¼û,ýÊÿ±ÿ'ÿ|ÿ0ÿ^ýÇû ûú·ùýšþlþYÿ6ÿÞý üwýUý¥ý›þAŒ¥±ùa`ÿÄú÷ýö4ø¡ü]È ø Ìf© ÓµñzÿÝüû>ûêúÞü¯ýõü¬ýÍþyþ:ýüÎû®úAüÿtþëþOÿºþ7ýgý„ý ý^ýêþMÁïÓ2Û;üý÷ ö®öÐølþ!M¡ ;_> …•þþüqûüIûâüÍþŸþ‹þ]ÿÿuý•ürü“û˜û‚þuþâýÏý9ýƒûÿúyüÜü§ý÷þSéŠC­ `ÉþAúLöö×ö#ûÿ1ñR à s x¯±-ÿ|üjû/ûµûsþ@ÿŒþìþMÿÄýœüüÄû$ûòýZØšÿýOýåü‰üúüEÿ`½æ…c­Ùþzúèö8ö÷Øú+>ç Á 2có Òz×þ)üÖùËùœùßû;ý²ügýEÿKÿàý*ýwümûü ÿÌþØþoÿÿíýþÿãþÊþpÿ©“JÞ˜‡’1ü‹ø«ö¯õ‚÷Cýž« •X ‹ES þØûðû ûnüöþ—þßýýýý û™úáúWúÁúÏý(ÿÿaÿtþ1ýCünýþ}þ"ÿaˆZ²÷ó’Cý*øÿö6÷Qùkü3 ;˜ã€ƒ •+mnþ=ûüøùÑùãûü„ýÓýÕýCýüøú·ú ülýÕýqþÂý.ýæü8ýûý]þÇþóÿš(rìÅÿõüøù@ø ùdú{þFd5 OÄÃÍ Ü ¶H¼+lýbú²ùUúòûQü™üaýoý?üvûùú{ù’ùZùñøDøòøúÁûþÝþ„ÿËÿòß×zÿ=þ¶ýÒûÍúÿø>úŸûÝþħ?  á Å † ªPzüIúŒùÍùÛû'ý þ þ þdþpýUý²ûâùûøÿø}ùÚù/üdý†þAþ…ÿ³ ³ÍòTVÿµýbú ù'ù~ùšýBL« ÷ ËÔ% " 7¨"ÿû®ø‰øúüþëþ¹þG”¬.ÿ2üØùU÷-öËõÖ÷­øúJû&ýùþ¬Ç,‡ñJÖýûoú"ù˜û…ýùÿÈž` ƒÔˆ ì <q{þ&ü<û&üYýÝýÙüSý‹ýtýMý ü3û údúúû÷ûEüü?ûóüyþ…÷Xö›|ý¡ühúŠû+ýsÿ¦ƒ5@ å Æ / ² HB)ÄýñüTýpýüüû¬û*ü­ûŠûúùá÷Oø˜ø£ùæú6úDú úeü—þ¶˜'ƒP}æËþ×þ)ýŒýÊþ#jBºÌ¥ D‘ýv„ Ýþ=gþOþ7ÿîÿ,ÿ¬þ8ÿeþcýDúæöôIó»ó õÒ÷HøGù’ù\û"ý=ÿÔÿ§xÌÜüþ‹þDÿ™ÿbÿÀþØþlWÙ »ƒŠ6 C Ÿ¤´B9¸–ÿÆÿ þüÔù±öôó—ò§òó¹õ5öA÷»÷9ùÆúšüdü¹û üšþ›ÿEôª jìt â• “  Ç å ´ g wçþŒ:—ãµÿäþ`üvøgõWóÚòŒò•ôÑôõöø^úÝûüûßúzúÏûÀûÖüüûˆü)ýpþú+ƒø¤ÿ[Û© Ñ S ó O g ´n]£b ëªÄþKûÌø~ösõ}ô»õjõ¿ôÌô¹õ$øQúËûgû@ûEý?ýàýÐûGûéûÓü?OV|q…Ú } Ì 9 ¹ >Í´Ë÷“âWóÿAþZûJù'ø{ø×øÛú[û¼úøù£ù„ú2û†ú8ù#ø«ù«ù™úˆù-ùøù›ú˜ý¦{ebgk á ] å Ø ñ Õ㜒éÁ{{ý]ÿûTøIöÄõ²õSøú9úpúû¡üæýý0ûVù–úAú[ûoúúäúÆû‡þûÿj •ë½ Œ Q' P ó f‚xõ|©¹<ÿDü¯ùk÷köÀõƒ÷§øýøSùú5üÔýÙýßûcúCû¥ú ûCùáøùAú/ýzÿE±ÄÐõô ß Œ.8 Ÿ ‹]ØQÂàšÐËÿ þ¦ùÔö£ôàóô"÷%ùCúóúüiþ³ôÓþ÷ükýüƒû[ù8ø›ø¡ùý¡ Ñ¾sò ƒ¬´ Ž  S Š(Ÿ†XrÿUýOùöéóÛòòSõ¤ö6÷{÷îøuû¤þ)”ÿfþ×þzýœüú¬øùøÁùý«ÿ•+ÊÐ Æ 5ýø`Ø  §ÈkÖÀʸ/âþäüðøEöùó@óÉò õö—ö±ö øûãý0ÿÍýlüùü3üNüÜú˜úRûßû«þDÇÎèò¼ — Ÿú'’ B ê ÄA  ðø›èáÿ0ý£ø™õãò'òGñ3óôBôÏô&öùýÿ„þýÖý”üü¬ùóøoù úDýÿ—4n$ü ” PBºú w x  Ù{òM ŸbïY”Ðÿžú¦ö]ó,òBñRó ôáóôïô¨÷û“üÇû ûü2üÌüAûÇúXûêûäþ<C($³ v †L~ˆf† ¼ O î[žUú¯ÊûøcôXòmð{ñÕñbñ¯ñüò,ö‚ù/û¹ú,úÝûˆû±ûÇù/ù²ùQúyýÿ²#š8Z ¬Y‚k&§R Œ Žq P Ôkžü† ûå÷·ôó¡ñìò,ó]ò>ò­ò<õMøúHù-øsùóøOùn÷âöŠ÷øiûDý/“¬­z à `±VÄ}3 û É  p ?Æ”¶Ó³DýúÂö`ôLòóåò=òˆñþñœô¦÷ˆùËøpøúïøNùüö=÷Õ÷_ùéüàþ£œó9Ù ¶\/ðAâp ¯  š ëò–aû)øDõûóƒóËõ¡öwöÖõÃõÎö ø øFö]õßö„öƒ÷3öšö$÷ø¶û³ý2áe{³ Ý ®¸°Õ 2P ¡ j d ¥ P štpÈÕÿ‹úd÷vôéòçñÄó,ôBôPôõÊ÷ûüÛú}ùúá÷Ž÷Fõ2õ[õ ÷ú?ü¼þaßîš ÎÒ1m£H@ h  q  ’·€[;ûøõYó`òTô?ôéó=óçó5öËøìù¢øô÷ù£÷”÷ˆõ.öŸöçøÌû5þ!¡}<3y 0yÛû]J é H =†  D ðëfƒüzøô8òÌðò:ò$òcò8óö\ùãúüùoùÍú9ùøøöõõEõ÷¡ùßûÄþøÿ”|Þê loQ3u‘ ] S h : ô xÚ=\ôýÄú­÷îõ>ôYõ<ôçòíñüñ]ô^÷–øc÷Z÷êø øTøeö÷îöáøEûœüÿÂÿË1R' æ¾ÚAà ó Ü ½ ù  žó |(þxû†ø+÷Üõ ÷:öõÜóåó“õñ÷Åø÷Àö™÷öÝö¤ôÓõwöšøzûúühÿ/„¦l 𚃈t‡ _ £ ù C + ŽÄOÚÁ&üYùšö7õôÆõrõ õÆô–õ¥÷ñùuúÀøž÷Ãø=÷c÷¡ô`õžõª÷ÍúèüËê®*A Û³ -< µ Ö}“ ½ ( ešê± ýäùÿö|õô¹õ`õõyô õg÷$ú(ûRù¼øú~øøôõ°öÀö²ø´ûýàÿŠTÍ@… Eü¿#A= 4 º g Ý Y #ݼÂhuÿAû¾øößôô#öÍõlõõÇõÌ÷˜ú û>ú ùÕùú÷üö\ô€ôµô÷-ûðýÈGªz# X“Ζüq # š3 Á÷³¯âípûrøõ óèñ^óøòó.ó¹ôy÷û¯ücûùúMüØú5ú@÷ŠöÞõ ÷jùû—ýÜþ’ÙÝ Yð@lŠ$'Ø  e • ÛÁÀíT3ýÆøjöô8óƒò¸ô’ôðó+ósó¸õVø¬ùnø¤ø’úðùYúø7ø¼÷ZùÇûýtÿ1Ø, ú8¾¬to ë # . [ „2ªÞüÂ÷$õÌòýñ§ñ!ô&ôÚóCó¨óSõ°÷_øÀöÒöèøfø¶øŽö_÷÷Tù¾û‡ý/B\ãr B ÂNjÎ÷èL ø +  Õ Â Ù * Œ\±ÿêùlöó„ñÓðÕòÈò—òøñÐò»ô]÷Î÷Âõ¡ö9ø÷Ó÷Wõ0öVõÈ÷<ú}üŽÿµ Ô „Ù—Þ{Æ C 1 $ A ˆ g ¥ ½ ECû¸øúõSô"ócô‘ópò„ñ<òŠôo÷øAöZ÷û÷V÷Ýö¾ô}õÜôøWúóüÙÿz¥4 $›*@̇ A · Æ c o  K $86þrùÇö>ôòòqòEôüóóôòˆóóõû÷÷÷Ýõ2÷ø÷3öô‚ôôüöùIû þûm /PÕMC R w r   P 0 Z|lÛÿ€ûøø3ö`ôPô¨õŸô÷òÓñòÙóîõ×õ<ô ÷øÕø ø”öžööùø2úŠüþªÿ;²Ñ .,j6Ä`«s Þ ’ Ð y d¨×êütøßö.õÛóºôQö±õ¤ôˆó¡óoõÜöæõ1ô†ö„öˆö¹ôÙóÿóÍôÆ÷ù°û‘ý_ÿkI i€ï/RÌ Û Ö \ s i ߬ïùùú#÷Æô²òÂñcóõõô(ôôPõç÷°ùRø*÷ÿøš÷;÷Qô¿ó~ó¯ôê÷0ùîûDýÞþ³Ü ª’—{E; 0 ZOÛ ä X €ØIû÷Ôó‹ñAð´ñïòóò€ò¨ò9ôx÷šù:øøÉùÎø ø°ô¨ôõó‡õ¿÷Wøcú„ûzý»G¢ ¼šÀ ú …ŸR:ã s ¦.\ û­÷ôøñµðòwòÅñ¯ðþð¸ò¿õóö¼õ"÷nùÍømøkõ—õ£ôÊöãøWú†üÁýiÿ, Ð Â TG¤ ó 8 õ á sZÕ6o [ *—7ý„ù…õ‘òƒñ¬òÆò¹ñòðRñ®óƒöš÷Þõ’÷°øø÷”ö'ôeô¡óös÷2ùû¾ü ÿ*’J g"ЄÈÄ t O ƒ ¤ ‹ œ 6 ¢ Ž Àà"þûú[÷ñô‘ôÇõ¡õýó™ò@òéóÙõõõÂôR÷(øü÷"öcôaô*ô÷2øµù©úÅûùýkœ° Nþ¯¢ ã Í 0 í €  ô C 7 pÒ ©ýŠûzø§ötö€÷˜ö€ôfóÁó…õ÷ÈööJø$ø øxõ¢ôœôlõSø×ù"ü5ý¨þšg¢S °J¾uh µ Ð ” ñ ð ´ œ Ô2Kÿ‘ûIùœö9õ½õýölö@õôõL÷Óø3÷åö¢øÉ÷íö™ówóëò÷ôÙ÷ˆù ü’ýâÿ!´W i»¢bÛ å a   ÷ c ±UdÀýyú7øÌõ õböøt÷ãõõ‚õïö|÷Hõ¨öÃøÁøØ÷§ôÊôäóïõ¨÷KùLûÙü£þ@Šè ¾ ÖïÇ5” š<ÐB  œL('ÿÙùX÷Cõ^ófóˆõ÷_ö|õ~õ ÷7ùTù÷ªøÉøø)õzò‰òOòKõ¥öÆø…ú5üÍþ  ä .Nε § ¤ \ŠEŒ  ™ ”Èû›øOõÇò·òŠô@õ3ô½óÁó]öØø[øŸ÷kúÂúñùöþóWóõófö÷öø‡ù“úßüZt- Ï´ÈÊ—iu D y(r Ý Ø ²IsûžøóôÁòâò¶ôðô¾ó,óðóŒöÒø÷÷‰ùSüƒüû¹ö0õ¿ó’ô·õiöcø.ùûxþdqW Ç r>kå È ‰ º e±Zt2 ñ R .®aý¨úÁö>ôîó[ôüòÐñqñ'ó'ö²÷ÒöŠù—ûüCúC÷ÕööøéøõùàúúúküŒÿeM Q  Ž Ï   « @ à \ w ] ‡ Ç Æþ!ü…ù«öÆõ™ö:÷‚õ?ôjó›ôéö¯ööKùèù!ú¹öÉôóô¹õ˜øù"ûüšü}þ ~ µ ³e« ? Û Ÿ ” ¸ ‰ § ! µ à ¸ÀWžü×ùŒö›ôëôÑö!÷öOõ-õïöPøØöa÷3ú=úùˆõÿó$órô¹ö'ø½ú2üSýnJ¹D ã å v Å m úc u  e ‰ ø µ 9l€þrûO÷òô¶ô†õãôô!ôcõøÚùøIú¶ûû—øŠô¾óó¯õööéøûüû`ý Ô$ ° KS5ç f ¯   ® a j Û Ku‡\ÿ¶ü ú³ö¢õ¢ö†÷@ö`õíôÙö\ù}ù3øûfûûÏöÅó{òóöóö•ùþúü-þmNÆ Âº3™± É c ˆ X c e  Ž œ¹ëüíúË÷0õõøöT÷5öÊõÒõí÷ ú·øoùpüsüxûÆöõ[óêôðö³÷ ú ûÏûþ–8± W³1| Ö Ž º Ð È  Ï_þúZøõ~órôoö7ö„õþô>öþø„ú›ø¹ú©üü:úö õ¡ó'ö(÷tøxúéú ü<ÿÎê ò £!%#2')ð ã ‹ Àw«ý”ú6÷Ió}ñYò®óóáò“ó‰õ½øhùÒø üüdüù’ö¼õÖõ§øùÙúÁû“ûLü#ÿðW< f ¤  à 0 ý < aƒQÖå ¤ | þäûGøõôðóuôÅó¸ñÁð²ðHó©öëökøKü²üÎûV÷Ïõ—ô&ö¥øÓùbügý7þLAÉ` Ì ! Í Ñ ú € 5 N  q V ß [ ã ª *çþçüRù÷(÷å÷™ö9ô³òˆò¾ôôõoô!÷Gù‰ù¨÷1ôêóóæö«øÆú#ýçýÿù– W Õ × $ = K ¤ ± b s ó q ü  o T(ñÿ®ý6û‹÷öÖö˜÷DöÓôüó õó÷Kø…÷¹ú+û‡úµöÂóØòÂòÍõ—ö(ùÙúpû†ýȶ‡å 2wH' ¤ Ÿ 3† ¼  á k géþý¨ùFöxõHööôÙòó€õTø‘÷”ø’û3û÷ùEõótòôó¢öí÷îúèûšüðþ(û r ? Ò K n V h ¿  I Ù Æ õv¬µÿýÓù(÷¾ö÷úõô?ó®ólö¼ø±÷RúøûKûsø±ó½ò×ñwôöwø|ûwüÙý¾‹è c ¢ î ° 9 À Š„ S ù Ù .ëáàþïüßúÂ÷kö)÷“÷ÿõ„ôËó:õZøùÑøáû¡üHüÎ÷>ôÔòwòÔôrõë÷óùºú»ü\’Ë 1¶\½I ó h N " ¯ ä¬yþˆü…ùœöŸõ@ö\ö‹ôó”óüõ7ùËøòùQý ý¨û‰öbôâò×óûõÜöDùkú ûøü-F{û ; )LËq!W²ú ­ ë 3'‡ÆüŒú:÷õáôÊõIõëótó=ô7÷ùªø>û6ýšü*úCõûóÚòlõÚö¨øoûDüý›ÿc0m õ v K î | i k u >Ò ù T Q <ÎêýWûj÷0õlõƒõôóýñ;ñ´òøõ{÷w÷þûhýý"ù…õEô"ô÷¿÷ŒúýGþ”ÿ4_£è X B î !  ÷ g  B ‹ ¢ r ‡;ÑþWýú¦÷Ïöz÷ ÷$ô—òÝñ˜ó:ö öR÷ûðúúDõ óò³ó§öæ÷1ûJýÁþ@ØZ­ *od O h ç W h ] ð/ÂÿŠü÷ú!øÞõöf÷ö¦ôSó:ó¹õÓ÷÷…ù«ûãú|ødóùñãðdó3õÖö-ú°ûiýN¢+ñ i E H € ° · òÏëç   ¢ ’6Bÿü:úàö õÁõwößôçòkò’óö÷¸ö½ú¡û&ûV÷{óŽòò4õöÇø%ûüGþ2ÏÆ‡ ^  ø æ ¡   S' à êîhÿ·ýêúå÷ÆöÏ÷ÿ÷Ûõô[óbô¥ö5ö>ölùæø&øsó­ññ•òÚõB÷èú«üÉý…ÿl×5 â }  D " Ï N 8‹¨p _ Ö ón(ºþ5ý.úË÷M÷¾ø³÷ËõÙôãôA÷Qù‚øû@ý¯ü¤ù¥ówñ—ï›ñuóKõ©øàúþü'Ar ‘ › Ï š â J œ  îÉÕ › ` , MСÿýºûù÷Ç÷Ìøw÷YõEô¢ô¡÷Ýø9ø˜ûÝüüßøwô2óMòæô ö„øøú:üÆýæt=„ < \ Æ  Š Z  ’ ¸ ‹ ƒ fçýúýŽü&úS÷iöØ÷œøX÷âõ¹õùö°ù{ù‡ùýìü ü=÷]ôlóâóTö9÷ú¸ûHýÿCsz5 Û Ä û ƒ ½ o Ë 'V R @ à Û=HFýqûSøXõõ…öSöô`óýóTöÜø:øÌúÜýùýJüJ÷ÕõjôIöÔ÷Qù!üLý»þ9Xv' Ê ¬ ì  J î J   Í Œ i |öÀæUÿuý$üñøŠö˜ö2÷”õqóiòEóöµ÷Á÷Âûgýýnùèô|ó°ò\õ?öBù5üþ]œ>­ ° bE? õ à `   è ¨ X Ø [ÿ^f[ûØùà÷BõtôöíöžõôZóßô ÷¦÷aøNü¢ü üÐöêóãò®óöæöú ýCÿôG °P_ ò # Ô ì a :µ! ¡ RäÿîûúÒö„óógô/ôŒò]ñËñªôâöwöSùMüqü³úŒõ ôâòðô.ö7÷ŒúKü˜þ2­ ¨Ø¼w É Ü ? ™ ™kÖ þ Nìwáü–úðø/ö’ôyõ€ö€õ~ó”ò•ó3ö÷«öú’úÞùÍõñÅðÊðSô õùGüaþÌ ® ©q÷ ™ H  ? ~˜ó8° Ö _YÏmüzúŠ÷4ôóôËô^óêñôñ8ô\÷Ù÷iù0ýùünû“õ.òMðñóþóÁ÷>úý3†‹= )fäÌ Œ ¼ ˆRstd½ ¢ úOlÿ]ûlùöXóAó¼ô&ôòGñµñ ôåõ¬õMù±ûïûòùAõîó}òêô»õ÷ú_û„ýÈ} — OVi Þ q [ …G$% uÙ À ?˜üý®ûnùAöpôTõÆõ]ôòáðuñ÷óøôÓô ùúúö©òøñ`ò‘õöø‹úbüÎþžÃÍ ç »ËŽ > ä 0 3rÈy-P# ¦Iïýûø§ô†ó½ôõAóÇñÅñÅó¬öZöä÷ûrú ùdó¯ðXïûðÀóßôÊø™úýWÿw ï   ¶ ò  Q 3ãÎn¬B  úšý¿ùZöëõûö­õKóŽñœñÄó$õzôøÜùúf÷âòôñüð1ôrõ&÷oúÿû¼þêþÌ ƒ ” ¤  e 0 Ù ¬äÍyYÍ  èn?þµû†ø‡ö"÷¿÷5ö9ô‚ó·ô¶÷FøIøüÿû1û÷õ»ñ$ðÀïÚò0ó,ö¡øÔúžýEä XZÉ ¢ 3  T ~ëLvÍ Ø  Çþúü=úÍ÷=÷|øJøµõœó»ò_ôRöþõ?ø¹ûŽûzú!õbóò‚óbõöéøQú ü0þåÞá ò ê ?   ó ÏéÂEG „ E ÁE#þñûcø+öƒöü÷q÷ÖõÌô)õ4÷Gø€÷•úðû`û²÷tò ñúïéòô‡ö ù‡û%þï J • ô « Ä Þ 9´q °¬ Ô W¢NþNü—ùfö õsöË÷—ö:õ”ô¢öxùåùôú‹þ_þÑüûöäòñPñôOô~÷ãùü·þþÃd‰ Ü P Å  « m 6ë 6Ê Ù™ÔûýFüèøÉõùô.ö ö¬óò\ò…õxøÝøwüÜÿyÿ×ü²öóóÔñ:óÆôöŒù¼û)þ×c7 Ð ¢ Ï œ í ‘ X ¿G”ó ¦ ÍÇÿˆü»ú÷,õ¨õC÷:öôêòóbö ÷øoüþþ<úöIô|óiõ¨õ ø‰úaüµþZÛµ ¥ Ô£< ¤  U Ž  7ò Æ Õ g ; 'þaüRùõ£ó×ôëô óéð~ðcò•õxö¹ù\þLÿLþÝøÕõðópôeö±öÎùîûëýsÓ¥Õ h š › . . ˆ ³ `U G wì¤ÿ›üû¶÷~ôDôhõÊô¿òÀð%ñBó÷ôØôø€û·û@ù_ô^ó„òEõ.÷mùýÿLéŽ H nt˜ Î  ª D ¬uî»í j ÙßµþGýLûû÷ ö‘ö÷BõDòÊð#ñUóÔó«ô>ùÀùˆù¢ôCñðQð‰óëô²øAüÿ ø¼B /|&˜ m … ¾ 5Së| A r.îü±û½øºõñôFööôCò…ñ ó;õùôf÷ùúºúÇø½ò4ðMîðïôñÀóÐ÷æúþ˜™nš ª%<l z | ¼ê\=M‡% ‡ fª@ÿ4ýXùöÙõköyõòòñžñôóvõÊõÊùvûØúæö·ñšïNîkðñ§ó÷ úŽý ýì iÁ`!Û ˜ :ÔÌD{ Ö –U­ÿˆþ)üù÷øø€öËóò2ó—õ,ö(øRü¼ü˜ûÎõÀñ`ïïÉðßðöó„ö<ùŸüÊa ¾ 3h &yƒ:´;[=½ ë ùóþáýûø÷ÀøGø§õ|òñ óýôæôÿø=üãü“úõðò ñòóôU÷òø#ûGþG.!æ Á í ÿ G ° ã [SÁ‚X&[ m §ÿâýLü.ùB÷Ö÷(ù€øEö>ô°ô¡ö ÷É÷¼û¬üùû÷âòÀðMð}òîò[õøqúpý*àÒ ¸ ˜ … ¬ † k 0‰ÓÞ˜Ö* I Wþ:ýçúø|÷Ýøkùª÷ÿô˜óõ÷ôöÕùQý«ýîû"öøòëðññRóô÷ùäûØÿž7 ¥ n S ȸ¼£ ƒ [à«¨Æ e ™÷ZÿùýúÙ÷©÷ø øÏõ&óóÖô>ö*÷ŸûÎýîýYú#õúòNñóóìô¢÷Åù¾üÉ@#¯ ¦ Œ Ï ?  ¶ ¢ ¼ (žÎ. öOµÿžþuüxù7ø>ù­ù\ø5õŽó¥ôïöX÷æùóýâþÕýõ÷Zôòò‚ó\óö•÷úqýU…¾d ( æ ˜ ã ˆ ©  ç ˜«V˜ m z¼Õhþ¼ýûÚøÞøpúNúþ÷óôíó4õ¹öòöuûFþÿsü^÷Fõ?ó¶ôâô)öYøþùwüòÿaÉ ò  â Ô ¤ @ Z £n U ªM Eýü±úOø÷ÕøGú†ùëöéôLõ÷Œ÷üøSý7þþqùÆõüóó8õŽõ7ø]ú§ü¯ÿ\W5 ã _ « Ü D ) 9 ˜ ¿ ˆ˜HU ‘ º¡cþâúúÎ÷¤õØõøùµ÷]õ`ôlõ÷'÷…ú”ý;þWü½ötôròéó õ+öôøÂú@ý¯Mî% 8Ü” 7 / £ µ . ãb‘è¢ ¯ µ[güÐùøÕôÿòøóAöˆöõó®ó¨õñöÔ÷SüTþ¯þ ûÄöÓô‚ó.õ õ÷jù§û™þ^þ ¢ {[ž Û •  í ”"›•A¹ Ç Ä6†ü=û¥øgõgôÅõ–ö-õòÅðÑñÚó@ô:÷ ü!ý6ý ø©õôLôÔõ=ö§øsúnüçÿô¤ iä § ¤ ê R xSÀ©Ä ! ?)ÿÆû<újöÍóªóEõõ'ôòÑñzóåô;õÄùŒüTýûIöõ óPõÕõ÷gùãú'ý¹iÆb V𘑠o ˆ   ™(“3€q• Œ#ýû~øÃô=óOôÇõXõRócñ«ñó`óõïùXû£û)÷fôvó—óÓõö‚ølúÎüèÿ«¬ ʹIŽ ³ a ÷ Ù¤ d½7 a 0adýðû[øõ²ôúõ[öþô©ò¯ñ ó´ôèôKø‘ûyüYú”ôÕòñŸòµóõ øúÞüˆB@+ dpVHÁ5Ñx¿7"y É 6Hÿùüèú ÷íô2õyöêõ ó]ñ±ñxó6ôþô}ùYû¯û©÷Ÿó±òòFô¯ôæö ùû¶ý‰ý û gÇ­ < Ÿ } ¹ xdœn\  N þPýHú÷+ö›÷yøØöäó]ò ó%ôÎóöçù’úÃùSô0òð$ñçòÙó2÷wùEüÈÿÐàú W>l “ ¥ ã £ùº3D• 韛ýÊû,ø—õ×õ:÷3÷[õxó·ó)õöFö$ú!ü;ü›ø’ó%òxð0ònò;ô÷aùUü…ù¹ €>… Ö : ï ›ý¢ý7© ã š7Fþ‘û¿÷&öÅö³÷1ö¥ó"òåò¶ôõ¤ö$ûøûÐûîöÌó¥òJòÑóôköqøLúþü¯Y L ªw Ì B ¦  ¾ªT× u8 Ý Ö¬ÿþ³ú¶÷U÷Žøpø,öÒóGóRô-õCõùûûpüÿù«ô¸òñíñ˜òìóÒö\ù2ü²ÿ8)Ì !ÔZ :  : X 4þÎÝ r 3ÉÂþÀü?ùœ÷}ø‚ùQø¿õ¢óïó°õ=öy÷üŒýÚý/ù"õLóôñ9óÒòÛôøö3ùûû›ÿMRª hÄ! 5 ­ ß ž ¹êt²Ú Ï ÞB£þïü—ùwöcö"øùW÷Mõ¥ôŸõÞözöù’üýÔûmöìô–óGôžõqöÀøtúQüËþ''í ¬ ç U Ì ‘ F  P­WœÈ ~ ™ïþ.üaøö¢öOø(øöEôWôÿõ%÷Ç÷7üúýÒýàùÇô|óÐñIóôöÓø:û%þ¹+ 7 ¿  ” X  5 ËÈ{éú Ü Ù$þjüéùRöWõ…öI÷#ö¬ó‹òîóéõ!÷úÙþüÿëþõøÝõ–óæò§óºóZö“ø„û¨þC®l ­ ÝF # R · ® ì ÑPȆp ; Úýþú!÷LôZô]öÕö õìòòòxôÂõBöôúûýõþBü/÷Eöô£õ²õŠöÅøzú ýg×Ýa —JŽ P  x ³ Í |ÙqIb õ \·ýDûø‰ôÔò ôšõõóéñíòßôøõløÝýˆÿÀÿlú÷°õ¤ôüõsõ«÷aùRûþ Û› } J]‹ ,   è þ ¿Q:ú x ªüÒú5÷äóoóÑôõ-óMðòï6ñ4ó2ô ùý'ÿiýÑ÷}öÖôøõ$÷{øRû9ý´ÿÄŽ}J &äå ½ Ö ‚ ! û –Åˆí ¦ œ5þ¯ûZù~õDóô¬õüô•ò ð©ðòñ®òÜôWúwüGý«øûô°óÑòÄôðôž÷IúêüRGóG ónÚ„³ Ú ¢ c ˜çpòè^ ±¯Øû¼ùBö®òåñ‰óUô;ó¨ðüïÍðJòóK÷üþ”üÕöíôøò†ó„ôTõsøÇúÀýg ¹+ ­“LÓ ¨ © * û ó¯+`è ? ªöühúGöcó“ó¹ôÓóeñïîîðÃðÇò\ø9û°ü™øÎôÂó©òbôxô½ö¢ùü“ÿƒÐ ‰u‹Ôbü ú ¨ –dƒ¾£ 4 )ÂUþüHù†õAô€õíõôñfï\ïRð“ðAô ùOûÇúTõxó»ñ÷ñZójôx÷öùýøö¬ ´»Õ{‰ò  pËèLSk c uÿürúÿöNôÌôöÌõ:ó‚ðÀïüïµðÎñäö}úKüù¹ôDóIñ2ò:òêóªö@ùÈü j ö *>î¥È’Õü2b=( „ Ù•þ8ü$ùNõ[ójôüô˜óýðgï€ïLð•ðÝó£øûûÕõ—óÜñ…ñÅòöò¯õþ÷çúqþ+Ø Ù s— /Ø Ë •ß Ôá†' þtÿZýuùRööO÷¾öFôýðûï-ðxðúðaõÍøÈúø÷CóÎñðöðxñóôõ™øÇûàÿÈZ †?ö 7 ~ Ì k øÂjÝW¼¯È ô³ÿ¤ü}øJö™ö÷võ»òËðÁðGñoñÍó÷ø‰ûüèöÀóŸñðêð|ðÌòHõxøküÿÇ 9 Þ’± ¿  ¨ * šîì²pø e ù9ÿ³û?ø¨÷ÈøzøøõµòjñFñ‹ñÔñòõÊùDütúàõ™ôCòÆòŸòîòíô‘öfù\ýKvR   Ï ò  e e÷rí}àÞ X ñ®þüýø2÷8øRùgø‘õ?óÈò2ónó#õËù8ü½üÎ÷ˆôÉòŠñÃò[òÁô ÷¦ùÿüšÙF @  j Ÿ Y ô c ¤ ÿ°Ö&Å U þöÿþ˜ú÷|öÚ÷ø öXó_òˆòëòOó:÷Üú=ýzûÌö"õó°óîó‚ôööùÜû¥ÿ<ùã ô ¸ & ) ù H ª pº7À Ë e 8CþüÒøòö½÷êø–÷Íôqò=ò×òóõºùiüdý«øšõ™ó òÉòNòKôõöÉùØýSDç å6 h ¢  o ž¼¯þ» cø»ý²ûVøãôˆôAöÉö.õæòïñògòèòñöÒú9ý¹ûýö™õaóàó$ôšô÷7ùJü"ÓŒš Ç À% ý ° ê A 0 ÝÙ¥Ad ¬gyþÔûÓ÷mõöÙöÙõWó_ñÛðþð.ñó÷|úûûZøØõô`ó\ôîóÁõ øÙú_þˆ$ƒ ­ ¢.X à ~ # P…y ³ " ñPþ²üõùÚö_ö3øbø«öüó•òòåñ òAõgøú¦ø;ô©ò"ñòîòÙóiöíø2üYˆw¤ ø&°¦  > b 'û¤vþ*˜ ž ú·ÿýÚúU÷õÏõI÷ö:ô*òºñßñòô›øBû7ü øÕôó¶ñ¢òfò ô£ögùöü%û› = £ñ”j½ ã¶ožxWâ =Ûþ±ü†ùçõüôö¸öÿôPòúðÄð™ð÷ð¿ô‡ø&ûÉù›õ5ô‚òóaó™ó¯õÔ÷û[ÿ¸d ö1"Í ÷ @ ÷yÞtŠ, G ×ä9þÛûøŸõõõ ÷cö‰ôJò©ñañæðqò9öÁø¯ù›õâòrñÜðòòÞóåõ¿ø-ü ÌÜ ö ŸØŸlÍCÁW‚²‚N × >-þû|÷@ö%÷÷Eõ…òpñÖðÐð£ðÖó`÷ƒùiøúónòŸðqñòœòÈôÚöÿùßý+ v ^Á t³c¼@Ùž¿é MLDÿÉü$ùlöÀöË÷Îö®ôµòóñ‚ñ~ñ¼òÇöù'úö­òÌð¬ïáð®ðòôöPú)ÿ]M vúÀ Ò ™ “ ç7pRåjÊ _½þ]û¤÷øõ÷!÷fõEóýñóñ òwòÊõ9ùMû>ú¹õ²ó¢ñÍñòÔñaóÅôC÷ßú_ÿ £ Òfè · Û º '«eqÝ jI Š Í)’ÿ´ûÔø•ø6ùÇ÷4õÎòò€ñ(ñùñ_õm÷UøõòZñ9ñó§óöôuöøÌúzþO ± Á ) R î w l `Lø¦/°™ Š —»ƒÿuü$ùÄ÷Ýø1ù­÷ÍõBôSôô ô‡ö!ù#únøgóñZïÇïýðƒñuóƒõ^ø.üO­l › fN D Æ ß sòŒ#6ìâ GÚKÿrûªøNøûøøNõdóóeóŽó’ôSøú¦ú÷$ó\ñ1ðgñŽñ¼ò”ô÷2úMþqìé l m- Û  6  d=/Áú  œ[ý{ù>ø5ù§ù>øö õÄôÍô‘ô ö"ù=úâø ôïñAðÙðáñcòôÉõ‹ø)üxé·  ™Œ Ö û ø r ›â > 剫6ÿ§ûåø„øùŸøcöŸôHôbôôƒõÏø·únûþ÷ôò§ð–ñªñ òô/ö0ùFýÁ§@ ªNµjz ü Àÿs e  yÿãüÍùløWùsù øõvôqôøô_õ¯÷®úåûæúiöêó^òŒò¤óÒóëôöõÅ÷xúþô÷ á л~J)R„­EÒ« E ˆú ÿÌüåùƒ÷¥÷ùÇøàöõxôôõ°õËøÇúÉûçøËô0óßñó¿ó¼ô'öÛ÷–ú þ>– -yŒÞ ð á 3  ¶Nß§c} ó Á¨þþ#ü²ø×ö¶÷Qøÿö õÐóûó|ôKõúö7ú’ûMû9÷…ôÞòÉòô»ôö÷íø‚û^ÿ^  Ô~Ñ’¼ , Ò F£EŽ R ß™ÿïüàùêöör÷f÷µõèóHóxóô¼ôé÷{úrû.ùäôUó òióœô¯õ÷¥øÌúêýæHþ •‚Ñ)7È € ƒ ¯ Óäè œ |ÇÜþ-ü¹ø~ö¿ö†÷†öLô~ò>òºòqónõ[ùtû¢û÷^ô[òâñ]óÛóLõ¯öðøªû¥ÿþÓ Ö+ëÇ› ³ ½W¬² ø + ½Oïþ¨ûø‚öúö6öàó\ñð=ð?ñiòölùKû©ù›õ¸ó@ò£óâôîõ0÷|øWúGý!s1 ú ZSñ:Æ " ¶ ioè,Ö  ¤‰ýbþøúøMø»ø8÷¥ô>òIñññµòÜõø|ø/õlò·ðõð!ó„ôZö¥÷”ùüôÿ´ ;¨OúÂd*»õ $œ Ì æ­þÅûãø©÷øÊ÷ öÏóVòò€òGóö”øòù=ø ô“ñÒïÏð7òŠóRõãöNù“ü­è ÍëÍ)繸 # / Ï Z·ýiúøŠ÷Í÷îö¸ôÁòÿñùñòôó¬öHø¢ø€õ0ò6ð¥ï¥ñÕò©ôöË÷úYþ¹ˆ. ðÇÒ³«¡à+¥ñ‘–; ­ »%¾ü@ù:÷üö™öEõ"óÈñ¹ñ”òuóðõSø¸ùø®ôüñïšïËð òÄó)õY÷túÉþ›Â fÛ²h1Ù4˜ŽÝË . A ”ÇÍÿ_ü«ùWøø÷ñôÔò“ñnñòMóöç÷©øöóÖð¥ï÷ð,ò¹óèô•öÛøpü›) =í°*›ašH#•Ÿ ] q  ÙýŸúÀødø[ø÷¦õ7ô‹óÙóeôùõø ù®øKõ®òBð ðŠñ‰òôÞô€ö ù×ü6 Ì €1–§¤eh¬ øÏ & R Èþiûxø[÷=÷Ôö¸õÃóóÿòÜóèô÷ÄøžùÈ÷–ô>ò`ð=ñ‚ò'ô õ÷éøÑû’ÿ³fY L„ 5ýÚüMå E †“&þûúŽøã÷³÷Âöõvóóqóôtõž÷ÕøÓøåõöòð°ïñ–ò£ôöøúþ?¡) ž‡ù#w;ΦÄ6†:Ö c © ¨ÿüØø ÷¾öyö‡õüóó óçóÑô¨ö^ø*ù/øüô’òGððzñó“ôö>ø=ûZÿçóR ~¬ðÍ}%cn:Ž ‘  EwyÿgüÃù|øè÷¼öõô#ó|òçòÍóõN÷Óø5ù÷9ôÅñ;ð6ñBòãóõÑöÒø ü+à Q3rö¯…{Ë%×Ó ² © Tãëÿ·üÎùÜ÷q÷P÷@öfô÷òŽò^ó6ôÀõð÷Âøvø¶õ^óAñÜðòjó@õ¤öbø‰úûý¾KÄ AGúuÍÃwXLubše ê r ØÊÿšüÃùhøø÷Œõó¦ò½òNó+ô[öò÷©ø†÷ùôÐòÜðoñYòðó”õl÷ù®ü©ä³ ¢ @C”Q7Níà9Ì¡  ) íCLýÔù“÷öö»öáõhôuó‰óKôQõÑöø<ùÅøEö•ó@ñQðñ&òáózõd÷Ôùýdžk `¤ŠÓôjŸ9EŠÌ C × Œ3ÿû%øeöÞõVõ7ôäòaò«ò¯óûôU÷0ùÞùÑø7öÛóvñ&ñzñÊò’ô9öiøjûIÿ…›, ˜p&Ã@^Á|ÞÍ÷  ¿  ¨_§þ´ú÷ ö õ·ó2ò ñÙð˜ñó÷ôh÷ñøaù¯÷Šõóhñ|ñ'òåó…õ|÷Äù,ýÍ2ø ÷ Álf@`•h%#Þ ª  ÖŶþ’úø©ö#õ„ó±ñ“ðPð$ñ|òlô½öì÷µ÷öôûñZñáñ5ó õ|öšøGûßþȇ' Éìç:‚£ÅÀõÂÐXˆ ¼ =Ã5ÿ“û€øÎööçô†ó ò‘ñÏñ¯òâóö{÷õ÷¡ö›ôTò/ðÊïPðò²óÇõLønûgÿÈíf Äs`oÖäR ¢… b Ë8mþ·úô÷•öqõèó]ò2ññxñXòôCöš÷»÷Uö–ôSòñ×ðÞñoóõ?÷ùïü¾Æ © \Û~7†îªƒÚD q8ÿ © ð ·ý®ùýö~õ ô„ò)ññgñòçóóõ™÷ü÷>÷MõfóEñeððõñÅóÑõ6øàúXþ&â( ˜Ë÷HÝqKF‹´9KÞ l EèAJý¶ù‡÷ËõØóÙñ½ð ð ñ/òFôÇöOøø7÷;õ×òÚðùï(ð¨ñ–óöðøXün#< †Ž5°í®UsÂãá{² * ¢£’üÿùrø–öaô:òñƒðÂðïñìóùõ÷&÷öEô5ò´ð+ð¾ð3òô|ö-ù•ü\70 \xP'Äh·#Ýš÷à f W·ý>úøgö„ôÌò›ñMññ´ò{ô¤öø¿øâ÷SöHôPòñ»ð}ñçòºô'÷ úŒý§«- µ. ÊI±=þÃ÷ów®™ ”NŽ›ýVúøâõªóªñ–ðXðÉð=òBô@öz÷}÷röºô±ò7ñVðàðMòAô¥öGùeüêÿ-ʰ »»ª”$Ÿ5µ—~s^^ ¥ °hÆÿ€üú$øöô^òrñ@ñòpó^õôö¾÷S÷êõøóìñ<ð–ï+ðñªófö¶ùoýyr Þ N«Ô“Lú%2äJý¬ ´ V‘¹þiûÞøªöªôèòxñîðjñœò[ôOö´÷%ø@÷Åõ¦ó©ñð¡ï*ðwñ•óbö´ùˆý(€ ìBj‰QÐMد‡N vÌ  Ü8šþ™ûúø¥ö{ô„ò0ñóð©ñ óòô¯öì÷ö÷ ÷Žõ¶ó%òññ‘ñåòÝôA÷0úªýš â +s = ª:é›h">‚ $ÍW,þƒûùõöÔôõòØñÃñƒò§ó1õªöx÷÷ùõWôªòZñÑðñJò<ô¿öùÓü޽‚¤ Í Ò*MD9Y¨ë4Ö˜p — PûÞÿ1ýñúéøþöäô,ópòŸòcó’ô öR÷Ú÷†÷”öõŒóPòÂñÌñÂòmô°öùýcÔÝ  ä± ù׿,A±Q  G0(\ÿÝüµúÆø»ö¼ôHóÖòó×óõˆö÷¾÷÷îõ„ôió»ò˜òóZôöaø,û¬þÀÿð º 7ÜàzÜQü º µ ç j î Ž ˜su»ýSûVù‰÷ªõ!ô”óÝóxô†õÛö*øÃø{ø˜÷ ö¢ôSó€òmòó‹ô’öWù›ü}«Á& l¢30­>Çr3 º Ê ö `‰—¸ÿîü’ú—øwöAôÈòVòªò£óõÚö&øÒø´øÏ÷­ö]õRô¤óócôéõø û”þ—Íe  Œ`Œ8Ö~^ ó Þ ¨ ) Ë  à \¥þWüXúFøÝõÝóÀò©ò*óô¤õ*÷?ø‰øø ÷èõÒôçóxóÛóæô“öóøéûwÿ®ô¥ X ̶&‡ Ä“’µ‡¥ ¹ õ뿇ÿ°ü~ú“øvöbôéònò’òKó§ôMöÈ÷®øÝøƒøÊ÷ÎöŸõ’ôôUôXõ ÷ùµü…¸Æ ˜/‹Ý«›žA5 A Ó%$&„ý#û¨øóõ¶ó`òÎñÙñ‘òÑóUõ®öU÷{÷D÷çö<ösõáôÆôSõ|ö{øûRþ?5¯ r NhÇ—`1 罓.S Ý Û Ÿ^Ãÿlýûyøóõ ôýò§ò(ó%ôkõ¼ö–÷Ì÷÷!÷jö‘õÎôbôŠôAõ¸öûø¾û0ÿ¸î W ö Íç©wkz†yû í Q I ÿpÙ„ÿ?ýÖúCøÿõ2ô/óâò3óô`õµöƒ÷Ý÷Ù÷e÷Žöqõ„ôôRôGõ+÷ãù@ýù|A B †ê­>õ ¿ § ¤ « ƒ ß ¸  õž²xþMüúã÷þõ°ôôßó;ôõ"ö÷§÷ð÷ñ÷’÷ÊöÕõ.õ÷ôWõhö4ø³ú×ýt/Æ ³ ï T6ÿ ï ä Õ ¢   ³ ß»~"æÿºýŽûUù-÷sõ\ôÚóØóBôõö™öâö÷öÛöƒöõõ†õgõ»õ„öå÷áùpü˜ÿùË÷ – q Ž O ' , X ’ ¹ ” ñ Ì ïµb ÎþœüpúRø{öGõ°ôŽôÙô†õ‹öc÷Ø÷ê÷º÷8÷fö‹õùôäôHõ:öÊ÷úóüV²®!  Q í ý ë ö + { Å Ð v ° u Ï çÒˆ+Èþ`üëùŒ÷¶õ‘ôôôˆôqõ|öS÷æ÷7øDøÚ÷øöïõ0õèô8õ/öá÷Zú‘ý*t m ] œ [  ù  N „ ‡ & c * ”á  øÏþ›üXúCø¨ö‹õÝôÄô(õûõôöÃ÷køÍøÝøhø‹÷Ÿöûõ²õïõÖö{øôú þFKì » ³   ÷ ô    µ  µ5³ClpþSü#ú3ø¦ö|õÒôÀô9õöîö´÷RøÎøíø’øë÷_÷÷&÷ ÷šøBú¦üÿq$o@ ‰ $ 2  ì Ò Ä ¾ Ÿ 9 … €<é wÅÿùýüVúçøÕ÷ ÷©ö·ö÷§÷øcøŸø·øwøâ÷=÷Ëö™öÊö~÷ØøþúÏýÙÅQeõ ß  î Î Ò û + = ó + î\¤rîsÿêýIü”úùü÷-÷Ìöâöe÷4ø÷øùüùFúEúÕùùOøÎ÷¯÷øÝøWúüÿÅ54Èâq • ± Ö I c  ~ }$°/ä&ÿIý`û›ù7ø5÷†öNö‰ö7÷øãø|ùïù@ú=úÊù"ùšøVøuøùBúü|þ"¹úÉ, N * ü á Õ Ë ­ X µÊžMþœ"‘ÿèý5ü…úùü÷>÷ÐöÑö=÷ øîø¿ùvúûqûUûÈú úaùìøÚøHùbúDüÃþ‰2n/d ì ô É ­ £ ¥ µ « W ¯¬S鄬3ÿšýÔûúfø÷ö~õrõö÷Yøù•ú]û°ûwûáúGúæùàùLú4û¬üÀþ.«ã¿< 0 Œ y N  ß ¤ X Ýê«s(Èfÿþ›ü,ûáùÚøú÷E÷ÜöÚöM÷þ÷¹ørùúúÍú¡úKú úþùCúáúæû}ý‰ÿÔÌ ù _ ‰ ¤ ¬ x ' ” ´ˆ™(›wþèüQûÁùløh÷¥ö+ö öWö÷×÷®øwù6úÆúýúéú½ú¨úÞúcû?ü”ýtÿ®ÿ«ÚŠ Ã ® Ÿ ¼  J m D µ É‹®9«'®þ4ý¤ûú®øj÷Xö´õ”õö÷ø ùÇùHúmú(ú¼ùnùjùäùÊú üþAªõæw J œ « º È Ç › " T <ì‘Cßpÿÿ‰þ ý‰ûúÍø’÷…öâõ¼õ#öïöæ÷Íø“ùú<úïùwùùù†ùxúûûþkæ/‘¢ 5 g § Ê ã Ó ˆ ù % îÁvüoßÿaþìüŽûIúùÙ÷ßöSöHö¼ö|÷Føù¸ù1úGúú¡ùDù+ùyùGú½ûÂý)§êÁ, } ¢ Ð a ¥ Ä õ ýÀxC¨DÜÿrþ ýµûmú ùè÷þö•öÂöl÷MøùÌùXúšúzú)úÔùù¶ù"úûfü9þRpOëE8Ì; Ÿ þ Q } t  8 (öؾ‰Hý´ÿiþ(ýðû®úfùPø¦÷Ž÷û÷»ø|ù úsú¡ú„úú©ùNùJù·ù˜úüû¿ý´ÿ•,b^#²)ºZ ª  ØÚ͉0³*ªþBýü)û2ú2ù_øá÷Ú÷@øëø•ù,ú¶úû)ûüú±únúnúËú¤ûýÎþÁžÎ#B^¥¬; ¯oê0q­·•:ÅAÿÑýƒü?ûóùÃøø÷©÷á÷‡øOùúùˆúéúûÒúuú úÌùâùbúoû ýÿØ@Y'«ë c¸ 8$Ê.bŠÍ!áÿ¶þ´ýÈü·û—úùâøºø(ùöù×ú„ûòû üÄûEû¸úLú$úSúèúøûeýøþ|ÇÔͨ`²KÍØP›Ë e»õÝ©ÿ€þ…ýü~û_úzùùù—ùYúû¤ûþûüÌû`ûïú«úºú+ûüˆý9ÿçK6Ô:€°üt’ùÎ1D?Y˜êQ­ ^ÿÄþ2þvý„ü€û úúúúû®û"ü`üfü0üÛû‡û[û_û»û“üäýƒÿ&xUß)Fc³9è—/å. ïÊ·½Öÿòþ$þxýýœüüxûáú’ú¯ú?ûüéü‚ýÒý¾ýNý¯ü üžûûêûÅüþ¤ÿ6ƒT»í*X®ƒ¾±ZÍR¢ùJ­ÿ®þªýÌü#ü‹ûûúvú%ú0ú£úyûqüCýÑýþ þ¯ý'ý¢üQüNü°ü›ýÿ¼i°m¿ÑÌÁÞk©³yRƒ¬ñB‹Æÿßþèýñü)üzûÄúùùCùÙøêø•ù¿úüLýHþäþ ÿÌþ<þ¥ý9ýýaýJþ³ÿVÚës‘n4UÝšA˜ˆþ¿r8#ÿSþ˜ýçüSüÊû(ûRúgù¯øYø‹øZùŒúÅûÙü ýþ8þþöýáýþlþ=ÿhÐ! }vho¢ò`Ãá¼MŸÌêaŸÊÿÖþÏý×ü üdûÀúúFù³øiø›øCù+ú#ûÿû¬ü)ýcýyýýžýäýoþ^ÿ¸VÛðyŽbåê,•éï¨>=<Mgÿ©þÀýãü/ü­û;ûºúú‰ùùùfù#úûÖûxüãüý ýéü×üïüVý*þÿ?šãÂgÓèEÒK{:‡w??xÿŸþ³ýÀüêû#ûKúYùkøÄ÷…÷Û÷Àøíùûüºüýý ýý/ý›ýYþÿ¶DZм]ùT…€HÜFœê*[^-ÿôýàüüHû…ú³ùéøAøë÷ø¸ø£ù¡ú‚û)ü’ü¾ü²ü“ü…ü¨ü2ýSþùàaQ»Ð²‹ooƒGË/1I{¿úÿÿþýTüÂû7ûúÔù!ù¨øœøùêùäúÂûeüÃüáü×üºü£ü©üíü£ýáþˆKÉÉEhca{¼'žüýÈÙãùóÿ¬þmý^ürû‘ú°ùìøaø3øøCù>ú.ûáûDü\üHü.ü+üQü´üeý€þüÿ¤2WYz…™¿úHƒš)Ÿè/x¶ÝÒ¢ÿmþmý©üüZû¥úôùqùMù±ù{úvûdü ýaý[ýý¼ühü:üRüáüúýÿO×ë…¼ÄÄã4©*žáã‘ó#Q‰ÐÏÿ þ¤ýÓü ü1ûVúŸù(ù%ù¢ùuú[û,üÊü&ýHýGý9ý8ýXý³ýdþ†ÿøq¢e¿Í´•’Á#ŒÞóœhÍ<°ÿ9þsý¬üÜûûpúúúŸúSûùûnü¥ü›ünüBü7üVü¤üAýPþÊÿoé¦åàÆ¥ŸÎ o¸áÓƒvîaµÒ±ÿ‹þ´ýîü)ü_û§ú$úöùBúìúÀûˆü$ý€ý‘ýfý+ýýüïü!ý·ýÆþ.œÅƒÌÂ¥“§ø…"æöÅTÑMÊ?‘ž{aÿwþ»ý ýbü½û.ûÍúÈú%ûÄûcüÓüý ýàü¤ütüküüýÜý)ÿ½=bWHÁpÄ4NGܦjŒ¹¼Ëÿïþ%þYý’üÛûQûûRûåû«üYýÕýþüý­ýEýæü³ü·üýêý#ÿ„ÇÆnÄèßįµÌàïç¼h÷‹)Ü„ÿY§ÿÿ‹þþ`ýµüü«ûŸûüÃü‘ý1þþ•þaþðýsý ýÐüèüuý…þäÿ8Dè*,ößîR|“j!Æ\íyÛ #ÿQþ¥ý$ý¹üYüýû­ûxû†ûêûˆü:ýßý^þ¬þÄþªþ‰þoþhþ‘þÿãÿãÉqÊØÁš]61CYp„ŒˆrRØj¯·ÿºþ×ý$ý—üü·ûfû2û:ûŒû*üäü†ýþCþOþ+þýýÝý×ý þ˜þ‘ÿË÷ǽ–Zذ‹mN2ÚŸg*ãl²ÿÅþÓýôü9ü›û$ûÓú¦ú«úõú‘ûsüZýþ™þÃþ¨þcþþôýýýRþÿI\"‚|>ð ^-÷æåõ5SdKë4)ðþÀý¶üÐûû^úÝùŸù¦ùúØúÖûÕü¹ýdþÄþØþªþ^þþùý3þêþS~]ÓùíÂ…AɃ2á”T%Û†ãÿÿ.þjýÅü3ü°û;û×úŠútú¶úCûúû¦üEý½ýþþþþþHþºþƒÿŸ‚\ll]@!Ú–P䱩™dæÿþ6ýgü±ûû¤ú^úGúwúéúŽû5üÀü5ýý¢ýŸýžý¨ýÕýKþ ÿCw…F¤²›wO*ü͉2؉[HB$Ð7Tÿlþ©ýýü+üÖû—ûtû|ûÅûCüÐü=ýýŽýjýýËü™ü”üÔü~ýŸþ…Úë߬m-ôÊ¥{N"õɦ•€FÈôÿåþÑýãü,ü›û:ûøúßúîú9ûÄû{ü2ýÍý@þþ{þHþ þØýÅýôý‚þqÿ‘¨‡6#þÌ ‡v]6ÿ6D-Ñ õÿ¾þ¢ý¶üñûOûÐúzúOú]ú¸ú_û(üêüýþLþVþ5þþØýÐýþ¶þ«ÿÊײ8t…€rJÆ[ßj Úâ ÌÌd“Œÿyþ~ý¢üêûPûãú§úµúû­û`üüüuýÆýåýÑý©ý‡ý‚ý³ý:þÿ,LDòGXJ3!ëž3Âj@8W‰L¶Þÿéþóýý*ürûõúµúµúýú–ûXü ýÅýIþ‡þ†þIþþÆý¸ýõý’þzÿ„v.’®¤ŽŠªÍ×¼„D íëòéþ'ÿHþýûü‚üüÎûûˆû­ûüŸü*ý©ýþ[þoþbþKþMþ€þýþÑÿÖÛµ6F £3ã¹¶¸§‡j^|¹Lm.…—…ÿþýÂüü­ûnûNû_û¤ûü¨ü*ý¬ýþPþYþMþ@þRþŸþJÿ=_yaé»f Á|"§"®o~ÔSÔ†ÊÝÿáþåýüü2ü®ûnûmû©ûüžüývýÇýøýþøýéýóý,þ«þvÿxš£pæî°dà£KÙbÿÙöD¥èã‰ç,ÿCþeý§üüÉû¹ûâûMüëüýþŠþÈþºþwþþ®ý‚ý«ý6þÿJ†šdÑôá²yI*û¦;ÉnLeœÜè£ Djÿ‘þ¾ýýnüüêûöû+üüýýþ‚þñþ2ÿ5ÿ ÿÔþ­þÂþÿËÿ¼¸™.wzG½”‚n=÷¬{v¡ð(!¼Hrÿþàý>ýÂü{ü_ügü–üÞü$ý`ý¤ýíý#þGþVþ\þyþ¾þ4ÿÞÿ³r­¥}?üÀ†>ä”ceúSw9œ‘ÿƒþ˜ýçükü4üFü™üý¶ýCþ¢þÖþîþïþÀþiþþ³ý¢ýêýþŠÿ¯ÕÒ‹÷èžP¦,§9vðUim’¯ÿÒþþWýÅücü5üBü‘üýý þ{þàþ*ÿ:ÿÿÑþ•þ‹þÒþbÿ-ÿ·-egEúøéš?õÕãB&´6Zÿ‡þÌý5ýÇüŠüƒü¸üýƒýÛýþOþ…þªþ½þ½þ¾þÓþÿ˜ÿ;ü½eØ" å­~eS5 éÛõ'k§¤T¿6YÿˆþÏý6ýÍü–ü–üÌü(ýýÂýûý=þþ¶þÙþíþÿAÿ¯ÿ>í­Zæ=[J"ê®xJÒŽelª q­“W~ªÿçþKþÎýjý(ý ýýbýÎý$þeþžþÀþ¿þžþ_þþýý,þ¼þ–ÿ­ÎÌ}ÉÆ‹3è°›™|HÁšœÅ 6©*8ÿSþ¤ý/ýüüÿü1ý‡ýéýOþ•þÃþêþ ÿ ÿûþÒþ©þ¥þåþeÿïÃvï+4鮂c? È}·ú25ö‡úFpÿ¢þäý=ýÅü‹ü‹üÊü7ý¡ýôý;þŠþÚþÿ=ÿIÿNÿkÿ´ÿ*Èx.Å#R^B½y9ü¸ekµÙÜ .¯ ‹ÿüþuþðýwý ýÅü¹üíüRý¾ý,þ“þçþÿ"ÿ ÿôþóþ.ÿ¢ÿOï¦(r‡wL·r)Õ€H=d¥ùGV…Êãÿãþðý2ýµüvüoü•üßü<ýŒýÂýîý&þeþšþ½þÕþïþ ÿˆÿîЮ[Æòæ¯Wð™XÙ…šÉ Mz_òJxÿ}þ”ý×ü]ü ü!ü\üÅü8ýˆý²ýÈýÔýÞýòýþ#þLþ˜þÿ»ÿ‘}e&¬öÑr ³i#òÝù9‚Åïæ_‰“ÿ‘þ¡ýÑü5üÚûÂûöûgüõü}ýíýFþyþ|þXþ*þþÿý0þžþAÿé¨4šá äÉ k:"8l®ë är×(Y}ÿªþóýPýØü}üSüUüƒüÆüý~ýèýIþˆþ¢þþ‡þ|þœþíþ„ÿFÆD‘ª™e'òÈ’[8K’õeÆö×oÝ!Bcÿ þþ±ýýsýýŒý‰ýpýRýMýaý„ý¯ýßýþQþ¢þÿ€ÿÂk÷Y…}Gõªxg_\q´yËñÊYÁe¡ÿåþFþÎý‡ýqýŠýÄý÷ý þþêýØýËýÆýÆý×ýùý:þ¨þ/ÿÌÿx þ7I-ñ¦a'ôÑÀîaø‹ò È/vªÓÿÿUþÔý†ýiýwý°ýýý@þjþxþ{þ{þmþMþ%þúýçýþYþäþžÿ}Nûq®°{·bÒe‚ê‰;ÔõÖýÿþpý ýìüýnýÅý þ+þGþmþ“þ¢þ¡þþlþVþhþ«þÿÀÿƒ9×O—˜\ú—I¿Šy®šwGêc«ÔÿýþFþ»ýiýTý{ýÃýþ,þ8þCþ\þxþ“þ¶þÒþäþýþ!ÿYÿªÿ¡#ãñ«j-𺟿˜x‘R×H¦ôÿIÿ®þ-þÍý”ýý¾ýþ1þIþRþbþoþsþnþgþmþ€þ¼þÿ¢ÿ>àdÊ33¸g)òÁ—ª}öJN •ÿRœÿæþTþéý°ý¨ýÓý,þwþŸþ¡þþ€þoþ\þQþNþZþ‚þÖþSÿôÿ©OÕ+N@¬Dé›Y!"€¹P¢˜:¦áòÿöþþfýþüáüýŽý$þœþÖþÝþÐþ¿þ±þŸþ‘þ’þ¦þÔþ/ÿµÿ]ÈU¾ëÔoÐuñÿ“ÿ`ÿbÿ¬ÿ7ò­B‹|(¡ì(ÿIþý ýÊüÝü5ýžýíýþ"þ(þ,þ0þ2þBþ[þ„þËþ6ÿÎÿ‚5ÎJ¢ÎΘ6ÁLÔ[úÿÊÿÞÿ3«+„{1Á,…ÿÚþFþÐýýiý–ýîýBþkþkþWþ<þþþôýîýþ;þ§þ8ÿãÿ–,•à$ì³t.Ú‡@,WÄZâ*È8w‘ÿŸþÄýýºü—üÃü5ý³ýþEþNþSþ[þdþmþvþwþ~þ˜þÚþFÿçÿ›AÈ+^a.Øtœ?üÿèÿQÆG°ÞÖœ+¦ÿÎþ þmýýïü1ý¬ý*þ~þ•þþXþ/þ þòýâýÞýøý<þ³þ]ÿ-ý«.†¨>ÕiœGîÿ ]Ñ6qtGÿ…ãÿ%ÿcþ¸ý<ýûüýlýîýWþŽþ‘þvþUþ:þ#þþ þ7þpþÎþXÿÖ‡}½È Z÷•Éÿ³ÿéÿ\ìa¡’OÏJÿrþ¹ý0ýãüÒüýƒýÿýYþ}þþvþpþtþzþþ|þƒþ þÞþUÿÃ{ øò´f  4É€kçF€n+¹Hÿuþ·ý%ýÌüÂü ý|ýçý"þ+þþúýÝýÉýÉýàýþVþ½þAÿîÿ´x˜èÿâšJ÷¦VÛÇä+‹Ý öª]tÿŠþ´ýý¼üÍü6ýÈýBþˆþ•þ|þOþþäý»ý ý¤ýÎý(þ¾þŒÿrCö“ÿ'ÙŠ)Ä_ÓÍaÇ #è›l¨ÿÞþ/þ©ýhýzýÅýþVþeþWþDþ.þþóýÒý¶ý£ý«ýêýtþEÿ5$îŒÛà¬bÉBjÄ Ü˜0œòÿLÿªþ-þÛýÒýþbþªþÎþÌþºþ¤þ†þjþIþ-þþþ0þxþþþ¯ÿq,ÓN‚u4â=ñ´•¢âQË'QQ-ØQ•ÆÿýþUþíýÑý þ{þëþ3ÿ;ÿÿÑþˆþ@þþÜýÆýÇýæý+þ¦þ^ÿ3¾[ÁàÆ~¢ž@7•á%çv×>ÿ„þûýÂýìýUþÅþÿ>ÿAÿ*ÿýþ¼þrþ;þþ þ$þcþØþ~ÿ.àˆfv_8Ú”Dñ½¶Ò:IFC;Ê[Ïÿ:ÿ½þpþmþ©þÿIÿqÿnÿ^ÿCÿÿàþ þlþJþEþbþµþ=ÿãÿ=ÜS‹ƒKÀs(ôÒÝ UŒ•rA Ö‡$«ÿ/ÿÅþyþaþ…þÇþÿ!ÿ ÿÿÿøþãþËþ·þ¯þ³þÆþûþ`ÿæÿ…#³&cb4î¢ZӢޱ s»Ò¹a´'}ÿÕþHþüýþoþóþXÿ‰ÿƒÿ^ÿ+ÿîþ¨þgþ9þ+þ;þmþÉþSÿñÿ“3ÌO™£‚G³\þ¥je™ß!Ù“3ÀÿFÿÙþŽþ…þÆþ3ÿ—ÿÐÿÔÿ§ÿgÿÿÀþ_þþæýàýþUþÑþjÿ®JÙCuwSÍw#߸¸ë4_X+î­d›ÿÿ™þ4þüýþaþÖþAÿŒÿ²ÿÇÿËÿ´ÿtÿÿ³þXþ#þþ[þÔþwÿ"Ëkè9I%è—Dö«rO` ð+<-î±RÏÿ3ÿ•þþÑýßý8þ©þÿ?ÿJÿ<ÿÿäþ¡þcþDþMþpþ¬þ ÿŠÿ–œEU:½nÖ¥“­ßùÔœg¼ÿBÿ»þ2þÌý ý¿ý/þ¿þNÿ¬ÿÐÿÌÿªÿmÿÿ¯þPþ þôýþ1þŽþÿ¦ÿDõ£(p}RŸ9Û—uŒÙ.d`0ë¢HãÿgÿÞþRþßý¡ý²ýþkþÈþ ÿ+ÿ:ÿAÿ*ÿæþ‰þ*þæýÏýëýFþÜþ‹ÿAí„û@ZHÓ&ЄXbÅãáЫz2ÐÿWÿÑþVþþäýþlþ×þ0ÿbÿzÿ„ÿ{ÿSÿÿ¬þ[þ.þþ9þþëþ`ÿÞÿfñb°Ó˯…W%öÔÕû)=Ø„.Þÿ‡ÿ%ÿ´þ@þÙý¯ýÈý þ”þÿOÿ{ÿŽÿŽÿyÿ:ÿÚþvþ.þþ2þ€þÿ›ÿ-ºD» *Óp X(E•àùÍŽSÐÿ€ÿ#ÿ»þ^þ*þ-þ_þœþËþÞþÛþÕþÔþÄþ˜þXþ!þ þ$þrþîþ‹ÿ,ÁE¶ ì°t<Ö­ ½ï ó²Uåÿÿ$ÿËþ|þ9þ þ þ=þœþÿYÿ‚ÿƒÿuÿeÿJÿÿ²þFþîýÀýÍýþŠþ+ÿÙÿ‡3Á!J?¸`ͧ¦Ô.•ÛéÁkð]¸ÿÿjþàýzýUýzýÞý\þËþÿOÿjÿtÿ_ÿÿ»þTþþþ)þˆþ ÿšÿžj¡¹´›wKÏ‘rŽÏ %þÔ£j$Íÿbÿûþ¦þ~þ‰þ¼þúþ*ÿJÿ^ÿiÿ`ÿ:ÿìþþ<þ þþ3þ™þÿªÿ?ÒS¯äõèÇ•_Ó––ºÑÅŸ_ËÿŠÿPÿÿôþÙþØþÿþBÿ‹ÿºÿÄÿ¼ÿ­ÿ¤ÿŒÿSÿûþ™þJþ"þ-þtþîþ|ÿ«1¿¾¡^G1ëÍÌÝéÒ \Öÿ“ÿSÿÿ¸þrþIþPþ–þÿgÿ±ÿßÿýÿÉÿoÿÿÏþ¦þ¢þÑþ"ÿˆÿÿÿ…`žÁÎÇ·šj.öØßÿ ô¹_òÿuÿÿþ•þ2þáý´ýÂýþ–þ0ÿ¸ÿ:E;Øÿoÿÿ¢þqþuþ³þ*ÿ¼ÿOäeÃïôÕ¤m: Т«ñDrsHÿˆtÿÛþ<þ¸ý`ýFýuýÝý`þßþNÿ¦ÿñÿ-:´ÿQÿüþÊþÈþÿmÿñÿ} Îë㿚{b@áÃÆÝñõçʘY®ÿ:ÿ·þCþóýæýþvþÖþÿVÿÿ ÿ¸ÿ®ÿyÿ0ÿìþ¸þ¦þÊþ"ÿœÿ¢)’ÌåáʶŸ„dD/5PliDþ¡6Ðÿnÿ ÿ§þDþþðý þ€þîþNÿ’ÿÀÿäÿ éÿ¤ÿJÿõþ¿þ±þØþ1ÿ¦ÿ1ÁM°Þß½iL4õôDnvT¾Zûÿ›ÿ7ÿÛþ‹þ\þ^þšþïþBÿÿ ÿ¯ÿÀÿÌÿÃÿ“ÿJÿÿþÆþ°þÌþÿ“ÿª7§ãðÙªtEí¿  Áô&ð©Sóÿ…ÿ ÿ™þJþ0þaþÉþ>ÿ£ÿäÿüÿòÿÐÿ–ÿOÿÿûþÿLÿ¨ÿŠÞë³q>áûÉëûË}"Îÿ‹ÿVÿ!ÿéþ¨þ‚þŽþÐþ4ÿœÿñÿ#:A9Óÿfÿøþ þyþ’þêþnÿ°]òOzi4í§j6ÛÉÐãܼ„@óÿ©ÿlÿ1ÿóþ§þhþ=þGþˆþæþDÿ’ÿÌÿõÿ.#ðÿžÿKÿÿÿ%ÿqÿ×ÿNÐU¾õùÐ’_5øöQ‚Vü€Šÿ$ÿÅþeþ þÖýÚýþˆþýþZÿÿÄÿäÿ##üÿ¼ÿxÿEÿ6ÿQÿ‹ÿÖÿ9±,ÌÝÑ´•wY6 !<@(ð˜2Ïÿwÿ(ÿÓþ}þ7þþþRþ­þ ÿZÿ”ÿ¼ÿÕÿèÿäÿ¹ÿxÿ.ÿóþçþ ÿ[ÿÂÿ3¬ {´Â£o=þçÙÖó$SfK¢<áÿ•ÿLÿÿµþjþHþ]þžþñþAÿ|ÿ¥ÿÄÿàÿïÿâÿ³ÿpÿ0ÿ ÿÿ9ÿ„ÿØÿ3 i§ÁÁœn0é£hNZ†¯Á´ŠKÿÿ³ÿkÿ&ÿÞþ™þiþdþþÜþ.ÿuÿ¥ÿÃÿÎÿÔÿÌÿ«ÿoÿ1ÿûþçþþþ>ÿ–ÿùÿkáF޳¨ˆYè´x¿û$ð˜*¼ÿVÿñþþ5þ÷ýßýúýHþ¯þÿwÿ¿ÿñÿüÿ¿ÿmÿ!ÿîþðþ!ÿuÿßÿL¼(w¥­•c ÙAåÿòÿ+p ´žjÎÿ|ÿ%ÿÏþþJþ8þSþ’þÚþ!ÿZÿ{ÿÿ™ÿÿsÿCÿ ÿçþ×þïþ1ÿÿøÿkäQŸÒãØ²<ë™T4@g„U ²ÿ]ÿÿÍþ’þ^þ;þ>þiþºþÿmÿ°ÿßÿøÿùÿìÿ¿ÿ}ÿ.ÿéþÁþÂþôþLÿ¶ÿ&˜ú>bg]G.æ´iu§æð­@»ÿ7ÿÃþaþþËý¦ý¯ýïýYþÕþRÿÆÿ _|Géÿwÿÿ±þ‘þ°þûþlÿñÿyí@u”~Q¬Z++Y”¹®x¢ÿ#ÿ¯þHþûýÁý»ýïýPþÈþ8ÿ–ÿàÿ:D5©ÿOÿÿâþêþ!ÿqÿÜÿTÌ&\xsbQ+úÂ…\Y…Æðì¸_íÿqÿÿþžþ@þôýÄý½ýãý0þ’þôþJÿ‘ÿËÿïÿýÿëÿ¾ÿƒÿRÿ5ÿ9ÿbÿ§ÿúÿV°ü+>:*Õ˜Pïÿûÿ7„·Àa ®ÿXÿÿþ©þZþ!þþþJþ‰þËþ ÿIÿ„ÿ®ÿ¼ÿ¥ÿsÿ?ÿÿÿBÿÿçÿL² Lnn_K@.×K%$@SS.îÿ“ÿ5ÿßþ˜þ\þ2þ&þ>þ|þÈþ ÿ7ÿPÿ_ÿgÿnÿdÿLÿÿàþªþ’þ¢þêþ`ÿñÿ…~¿É¦q6 Ú d1(eµíþÞ”1¹ÿ<ÿÃþUþ þâýõý9þ’þéþ1ÿpÿ¤ÿÌÿÝÿÍÿ”ÿ@ÿßþŠþ\þeþŸþ ÿ•ÿ:äuÕùè¿„Fùž=îÿÇÿÚÿb“—{?öÿ¦ÿRÿÿ½þ‰þqþ~þ§þáþÿQÿ‹ÿÆÿ÷ÿ øÿ´ÿQÿåþþjþ{þ¸þ ÿ—ÿí'J\rŠ‘x<éšbR`mb8ñÿ—ÿ;ÿçþ þwþbþvþ«þÿRÿ”ÿÃÿäÿ&BF"Ôÿcÿðþ—þhþtþ·þ(ÿºÿXåI{Šˆ‚rRÉgîÿôÿ16) Øÿ™ÿOÿÿºþˆþzþ˜þÖþÿ`ÿ–ÿÄÿïÿJXC³ÿSÿ ÿìþöþ$ÿwÿâÿO¬æüþúûöçÔ±‘z€™ªœo!Êÿcÿÿ²þpþFþ?þ`þ þôþEÿŠÿÁÿñÿ"Mhg>úÿ§ÿcÿ=ÿGÿkÿ¬ÿRŒ©¨”€y~~zgJ<Eq©ÓÛ¿$²ÿ>ÿÍþnþ2þ þCþ”þôþNÿšÿÚÿ9VV0âÿsÿÿµþŸþÁþÿœÿ,µ=9èŸu@Ìÿ¨ÿ©ÿÎÿþÿ)A=%óÿ¶ÿmÿÿÚþ®þ¨þÇþøþ0ÿaÿ„ÿ ÿÄÿòÿ$FI'çÿÿ^ÿ<ÿ>ÿfÿ­ÿK}Ž€paI$÷ÿÎÿ­ÿ¤ÿ¼ÿéÿ,)Ùÿ’ÿ9ÿÝþ‘þ]þWþ‚þÑþ*ÿÿÅÿüÿ)Kl‡|RŸÿIÿÿÿ<ÿ›ÿô/8ôÇ“Püÿ§ÿTÿÿþþ ÿ,ÿNÿdÿkÿjÿKÿÿâþ þeþCþQþþìþUÿµÿþÿ6`‚œ¨™hÅÿ|ÿ[ÿeÿœÿóÿO¡ÓàÛÓÔÚѱ~7äÿ–ÿ_ÿ9ÿ ÿ ÿðþ×þ²þ‰þWþ þ÷ýåýðý,þŽþ÷þTÿ›ÿÌÿëÿ #:E<&êÿßÿðÿ$|á?~—‹i?"Ô‘IÀÿžÿšÿ¡ÿÿ‰ÿbÿ+ÿßþ…þþ¸ýkýGý\ý®ý$þ¦þÿkÿ¨ÿÒÿðÿ äÿ¶ÿŽÿƒÿ ÿéÿSÇ2y›–„tgJ'í¯wK1 âÿ±ÿ…ÿRÿÿ´þQþîý—ýiýgý˜ýéýJþ¦þûþNÿšÿØÿ *0ïÿ¹ÿŠÿuÿ…ÿÈÿ-™ô+>DH[if9ñšJ èÿäÿâÿâÿÙÿÍÿ§ÿ`ÿôþsþóý’ýiý€ýÑýDþ´þÿZÿÿ¯ÿ¾ÿ¼ÿ«ÿŽÿjÿ?ÿÿ ÿ"ÿeÿÑÿRÌ+csld`V> Æ{9üÿûÿûÿñÿëÿáÿÁÿ„ÿ*ÿ¼þSþþäýôý)þlþ¨þßþÿHÿƒÿ·ÿâÿüÿÿÿéÿ½ÿ†ÿ]ÿPÿqÿ¾ÿ{Àâîô"å±Z?-îÿÌÿµÿ¥ÿ…ÿQÿÿ£þFþþøýþWþªþýþDÿ~ÿ±ÿÒÿßÿÙÿ¾ÿ•ÿgÿ>ÿ-ÿ9ÿoÿÍÿD¶(!åæó÷Ü·paWD"þÿÖÿ¢ÿ_ÿÿ£þGþþþý%þtþÉþÿGÿpÿÿ¦ÿ¿ÿËÿËÿÂÿ¬ÿˆÿ`ÿBÿ>ÿbÿ³ÿØ'(*79'úÀŒ^?.$ ÷ÿÄÿtÿÿ¶þxþlþ…þÅþ ÿDÿfÿwÿ„ÿÿ–ÿ›ÿ”ÿ{ÿSÿ(ÿÿÿ<ÿÿ~ã!4úÛÑÉ¿·³´ÄÐÓ¸‚E Úÿ¦ÿkÿ!ÿÏþ‹þgþqþ©þûþQÿ¦ÿîÿ&M^S7 Ôÿ—ÿdÿ?ÿ.ÿ=ÿqÿºÿC_ifh†±ÒàßÔÇ¿º´ ‡kIáÿÿ-ÿÇþ~þdþ‚þÃþÿ{ÿÊÿ ?kˆ”ˆe,èÿ¦ÿxÿeÿxÿ°ÿY–«¡eWPGABIWlucSB&ÿÿÁÿzÿ8ÿÿÿAÿyÿ³ÿàÿ+E^nqdI!îÿ÷ÿ(mºìöÔ’KôÿÝÿÕÿÙÿãÿøÿ3QZYPE;)ÿÿ»ÿeÿÿçþãþ ÿPÿ¨ÿüÿL’ÉñùìÆ‰L8Õ"S[9Ò¥~Oëÿ¾ÿ¡ÿ›ÿ©ÿ³ÿÁÿÑÿÝÿçÿéÿÑÿ¦ÿmÿ2ÿ ÿ ÿ0ÿnÿ®ÿîÿ$V„¯ÞÿðÌ«—‘§ÕC\T3 ãÀ–j@éÿÈÿ¯ÿ˜ÿ‡ÿtÿlÿqÿƒÿ–ÿ—ÿÿPÿÿîþßþôþ'ÿcÿ¥ÿäÿ)h©áÿí¿‹ea„Ò;¨ú ð³r2õ¹{D Ûÿ¨ÿyÿKÿ'ÿÿ&ÿ8ÿAÿ;ÿÿöþÎþ¹þÅþúþLÿ¢ÿúÿJƒ³ÒÝÜÇ y\Vo¥öRœÌØÊ¬’zcQ<$ åµ…G¼ÿÿJÿÿãþ±þ€þ_þRþcþ–þàþ3ÿ†ÿÙÿ&l©Ûé®r=+H”sË ðÆ’b1 óïæäΧm,äÿ¥ÿiÿ*ÿçþ©þ{þ^þ^þ„þÆþ ÿyÿÎÿT€¥ÂËÀ›f-;ŽûW–¶¸‚qhfcb^L(ú¹u<éÿ¿ÿˆÿ>ÿæþŠþ:þþõýþYþ°þÿwÿÙÿ+q«ÔÝŧ‡u~¢à!WqmW.×»¦«ÇçéÆŸs1Øÿtÿÿ³þgþ=þ5þRþŒþÖþ+ÿ~ÿÉÿ :`q^3ÿÿÚÿÚÿ _Ð:ƒ¥ŸU3 ./ô¾€M%þÿÑÿÿIÿþþ¹þ„þjþiþ|þ¥þÞþÿbÿ°ÿÿÿI‚™m>!!I‹Ø4*É‘bDCa–Ò 4G? ýذt*×ÿzÿÿÐþ“þuþwþ“þ¾þöþ%ÿNÿsÿ™ÿ»ÿÖÿàÿÝÿÎÿÅÿÚÿtæV¤¿­u+Ö‡F0W…§±¨zbQ7Úÿ£ÿiÿ3ÿÿòþîþÿ ÿGÿrÿ¡ÿÌÿúÿÙÿžÿpÿ_ÿxÿÂÿ+™û;Z]G!ñÄœ‰„„ƒuY6ùÿîÿáÿÉÿ¦ÿ‚ÿZÿ1ÿÿùþûþÿ5ÿYÿÿ¥ÿÉÿêÿÿÿ üÿÇÿ‚ÿGÿ(ÿ>ÿ‰ÿüÿxã0TX@ðÃ¥“›§¯¬d,ýÿ×ÿ»ÿÿ~ÿXÿ2ÿÿßþ¿þ·þÁþâþÿLÿÿÑÿW„‘t.Îÿjÿ)ÿÿ8ÿ‰ÿçÿ?{šœ“„sgnŒ¾ñ&ë³~EÏÿ†ÿ;ÿôþ«þpþMþAþRþ|þµþÿ\ÿ®ÿýÿApxRÉÿˆÿlÿwÿ¬ÿøÿ?v—™‚Y&óÿÎÿÏÿ÷ÿ=ÏôõÛ±…SÝÿ§ÿuÿGÿÿðþÝþÕþÞþùþ"ÿTÿŒÿÇÿ3E;½ÿqÿ@ÿ;ÿdÿµÿb–¦–n:ýÿÀÿÿ›ÿ³ÿíÿ0m‘žœ“€a1øÿ¾ÿ…ÿDÿÿÎþ¯þ§þ¶þÙþÿ\ÿªÿýÿHƒ¡“b×ÿ±ÿ´ÿÚÿNtjBÞÿ©ÿ…ÿzÿ‡ÿ³ÿëÿ0/ÿÿèÿÓÿ¸ÿ“ÿoÿOÿ7ÿ#ÿÿÿ ÿÿ2ÿUÿƒÿ³ÿæÿ"Y‡—…]/òÿ,^ˆ ¢‘i,ÜÿÿUÿ7ÿCÿpÿ«ÿåÿ,*áÿ·ÿ„ÿPÿÿêþ»þ’þ~þƒþ¢þÏþ ÿWÿ¨ÿðÿ:u˜•tD?ŒìBv„k-Ôj÷ÿ„ÿ,ÿ÷þçþùþ#ÿQÿpÿ|ÿ…ÿ‹ÿ‰ÿ†ÿzÿdÿKÿ3ÿÿöþ×þÈþËþäþÿ3ÿpÿ²ÿïÿ,X`M"êÿÇÿÓÿxõf»øå£;ÇUùÿ·ÿÿ…ÿ‡ÿ†ÿ}ÿjÿPÿ3ÿÿðþËþ¬þ“þ}þjþ[þXþeþþ¤þÚþÿsÿÎÿ-ŠÏëâ¶€YQq²ù<r—«¤{7ç¢ya]hmgBÙÿšÿWÿÿÕþ¥þ…þnþ[þSþOþUþgþ†þ¯þâþ!ÿnÿÀÿOmpV=7RˆÒXˆ­Â§x?êÐÍÓÑ»R »ÿgÿÿÝþ«þ‡þmþ[þRþZþpþŠþ²þÛþ ÿBÿ|ÿ½ÿòÿ úÿ8ŠõZ°âõêÊ–RÙ½¼Ðî #%ë²g³ÿXÿÿÏþ•þgþCþ6þ7þGþjþ˜þÓþÿaÿ¨ÿØÿìÿäÿÌÿ¹ÿÆÿcÜRµ1>0ý¹n2 5UaR'åŽ+ÄÿdÿÿÛþ¬þþ„þŒþ£þÂþãþÿAÿoÿžÿÆÿàÿéÿÒÿ¦ÿwÿ[ÿbÿ—ÿôÿiÝN¶:C!äš\6*=`‡©³žh¶Iãÿ‘ÿCÿÿÅþ”þoþVþTþ_þrþšþÏþÿ`ÿ¡ÿÁÿÁÿ¬ÿÿŒÿ¨ÿëÿI¯Y™Ìèá·ƒO'  5Um~†~\%Ù‚)ÊÿhÿÿÒþªþ˜þþ«þ¿þÞþÿ6ÿYÿnÿnÿ]ÿAÿ+ÿ-ÿYÿÿìÿ8‚Ç<bwzrms•©ºÂ¼¤y>ö£SÅÿÿcÿ@ÿ0ÿ+ÿ.ÿ9ÿ@ÿFÿPÿ^ÿpÿxÿhÿJÿÿóþâþøþAÿ›ÿýÿYŸÒû ûäÒÑà0gœÂÔÅŸ]ŸIÖÿ±ÿ™ÿ‹ÿŠÿ•ÿžÿ¥ÿ®ÿ±ÿ¿ÿÆÿËÿÁÿÿ_ÿ ÿæþÍþåþ$ÿxÿÒÿX† ¥”wYCDcÍ RНÁ¶‰Dï‘7âÿšÿfÿPÿ[ÿwÿœÿÂÿâÿýÿ çÿ½ÿÿmÿgÿÿ­ÿàÿ4Ut‰‹}a9 Cy¯Þ ߬t8ÿÿÊÿžÿ‡ÿÿ©ÿÓÿüÿ =VkvkKÚÿ˜ÿoÿmÿ†ÿ¯ÿàÿAm—®³›tH( !Ah­²œn6ùÿ»ÿ{ÿBÿÿÿÿ*ÿ]ÿ•ÿÎÿBp” ‘k80\z‘™•€Z2 ñÿèÿîÿþÿ$>Ul{{iDØÿ–ÿOÿ ÿßþÓþçþÿ@ÿsÿ£ÿÓÿ3PadYSVjŒ«½Á¼¶°©–wY;$!7[}•¤•i#Ïÿxÿ#ÿÒþ‹þZþLþcþ“þÙþ"ÿmÿ®ÿêÿ5IH6 *W”Ë÷"05* Ü n@!4OakgNßÿ›ÿSÿ ÿÃþ‹þmþqþŽþ»þïþ'ÿ_ÿ˜ÿÏÿøÿëÿØÿØÿ÷ÿ-z¼í.DTRB,óÚÄ´§—€mT1ûÿ¼ÿuÿ&ÿÐþwþ.þþþ(þlþÃþÿkÿ­ÿäÿ  öÿòÿ 4n¥É×ãçêéÝ《¥Àâ +CE0´Räÿjÿáþ_þðý¨ýŽý¥ýÜý&þvþÊþÿZÿ•ÿ¸ÿÃÿÃÿÅÿÛÿ V¬÷*FXcgY@뫞¤´ÈÛåéâϲ‡O®ÿCÿØþtþ/þþ þ$þOþþµþéþÿ0ÿ6ÿ3ÿ.ÿ;ÿfÿ¼ÿ(“ê'MemhQ0û':ELK?&ÿË’Jóÿ‹ÿÿ¦þIþþþþDþrþžþÄþâþöþþþúþ÷þþþ!ÿjÿÑÿC â "+44" øëõ5]„¤¼Â·›n7ô¢;ÄÿHÿÓþ{þJþ<þLþsþ¥þÚþ ÿ1ÿCÿ?ÿ0ÿÿÿ8ÿuÿÌÿ'm£ÀÓßèæßÕÏÞ:y·è é±t9ú¸i ÿAÿöþÊþ½þÄþÒþèþþþÿÿÿÚþ´þžþµþÿþsÿõ>fwv_0úÁ•zy޵ì*o«ÚóöãÁ‡5ÅGÁÿQÿÿáþÚþðþ ÿ1ÿOÿYÿQÿ/ÿÿÓþ¾þÏþÿlÿÖÿ4~²Ü(CI9# 6Tn‡~pY=î²g¾ÿ|ÿQÿBÿCÿSÿjÿ„ÿŸÿªÿšÿmÿ2ÿÿèþûþ6ÿ†ÿÕÿFk®Ê×ÕËÄÎçLˆÇú í¼„HÙŒ.Èÿlÿ%ÿÿúþ ÿ/ÿcÿšÿÎÿãÿÏÿ›ÿYÿÿÿÿTÿ¥ÿñÿ/Tk|‹Ž„n[R]y«é,zÁû$õÂ}"´;Æÿ`ÿÿêþÞþëþ ÿ9ÿiÿ’ÿŸÿ‘ÿpÿJÿ8ÿLÿzÿÂÿ @]hikk]Aùÿèÿìÿ:Ò/‚½×ÖÀj,Úu±ÿkÿFÿ>ÿDÿYÿvÿ—ÿ½ÿÏÿ¾ÿŒÿEÿ ÿëþöþ*ÿvÿÆÿ?l‹œ ‹d2ëÿíÿ <„ÔK]V:óÊœTÿÿ¤ÿMÿÿßþÜþúþ/ÿzÿËÿ0#æÿ™ÿPÿ,ÿ3ÿaÿ›ÿÔÿúÿ',,ëÿÞÿàÿùÿR–ÛDZWC) ä¬^©ÿSÿ ÿØþ¯þœþ›þ³þßþ ÿ$ÿ)ÿÿÿÿIÿ˜ÿîÿ=¢±µ¦ŠWÒÿ–ÿvÿpÿˆÿ¼ÿV°þ0HA+ ߤXþÿžÿHÿÿÜþÈþÉþãþÿ/ÿgÿ‹ÿ‘ÿrÿ@ÿ ÿôþÿ1ÿqÿ´ÿóÿ)\˜šMßÿ½ÿ·ÿÌÿñÿ*hžÇÛÞÙÔɾ¡b ©ÿFÿïþ¬þ‰þ{þ‡þ¦þÙþ ÿ"ÿÿþþÝþÍþèþ%ÿÿÜÿ(Xyš™ˆe4áÿÉÿÅÿÎÿïÿ$a•·¿µŸ‡jK!éÿ¢ÿ^ÿ"ÿïþÊþ°þ£þ©þ¾þâþÿ ÿòþÉþ þ‹þŸþÖþ&ÿ{ÿÂÿýÿ1Yx†{W)ÿÿãÿÜÿèÿ3v¸ï üÙ¬u2Ýÿzÿÿ½þ|þVþBþBþTþ{þ¬þãþ ÿÿ ÿðþàþëþÿRÿÿ¹ÿÚÿíÿ ïÿ×ÿÅÿÂÿÓÿõÿ*e¦ÚôûñÜÏ»¤|:Þÿ{ÿÿÂþþOþ6þ7þRþ|þ¢þ®þ›þrþFþ4þQþ þÿlÿÃÿ @cy|lB Ôÿ­ÿ–ÿ—ÿ·ÿìÿ:ŠÍû ûäÁ’c$×ÿ†ÿ;ÿÿÙþ¿þ±þ±þÆþãþÿÿ ÿßþ þcþ?þBþlþ©þôþ?ÿŽÿÙÿ X|z\-øÿËÿ¸ÿºÿÒÿÿÿ?†Âçý  ùÆz©ÿ<ÿÝþ‹þLþ-þ#þ8þiþœþÉþÛþÑþ¾þ­þ²þÎþÿþ-ÿVÿuÿ™ÿºÿàÿüÿ ðÿÒÿ·ÿ¨ÿ§ÿ¼ÿêÿ+x¹çúöêÖ¹’[Ìÿ†ÿEÿ ÿÝþ¸þšþ•þþªþ³þªþ‘þgþDþ8þUþˆþÊþÿPÿ…ÿ±ÿÖÿóÿÿÿéÿÍÿ¸ÿ¯ÿ°ÿÄÿíÿ!Z‰¦±¸¾¸²™o0èÿÿOÿÿÇþ–þxþzþ•þ¸þÍþÍþ¶þ‰þeþVþhþŽþÀþôþ'ÿVÿ‹ÿ·ÿÜÿìÿëÿáÿÈÿ«ÿ›ÿšÿ«ÿÔÿ]šÂÒÑĺ²šv<ùÿ·ÿwÿBÿÿåþ¹þ¥þªþ¾þÒþØþÈþ©þ‰þyþˆþ¨þÒþÿ$ÿCÿ_ÿxÿÿ”ÿÿ€ÿhÿQÿFÿMÿbÿ—ÿæÿB¡ì#ûâ¸>ùÿºÿ€ÿJÿÿûþæþæþÿÿ)ÿÿøþÆþ þþ—þ¸þæþÿFÿuÿŸÿÊÿèÿùÿêÿÄÿ˜ÿpÿGÿ+ÿ(ÿCÿzÿÄÿ^—»Öêú÷ךTÒÿžÿpÿGÿ*ÿÿ(ÿDÿaÿjÿ]ÿ;ÿÿÿÿÿ;ÿXÿoÿ€ÿÿ¡ÿ±ÿ¹ÿ³ÿœÿ„ÿqÿeÿcÿgÿyÿ˜ÿÊÿýÿ,GU`qФ±¢}D Çÿ†ÿLÿÿôþèþûþÿGÿcÿeÿUÿEÿDÿ[ÿÿ¢ÿÁÿÚÿðÿüÿØÿªÿ€ÿbÿRÿOÿWÿsÿ›ÿÍÿ+?JN\uš‰_/ôÿºÿ‡ÿPÿ ÿ ÿ ÿ,ÿWÿ}ÿÿlÿMÿ9ÿ=ÿ_ÿ‰ÿºÿàÿÿÿ*2/Øÿ½ÿ©ÿ¡ÿšÿ ÿ­ÿÌÿîÿ '!(AU[I&ûÿËÿ›ÿiÿ6ÿÿüþÿ*ÿUÿzÿ‡ÿÿ{ÿ€ÿ–ÿ¶ÿÝÿ"7OfpcDÝÿ©ÿŠÿ{ÿxÿ†ÿ§ÿÓÿ);;6:LhxnRßÿ¤ÿgÿ)ÿ÷þ×þÑþâþ ÿ1ÿLÿOÿGÿJÿdÿ•ÿÚÿR„¨ÂÓÏ´„I Ýÿ»ÿ£ÿœÿ¤ÿ½ÿÙÿöÿøÿèÿëÿøÿ íÿÆÿ ÿ{ÿYÿ8ÿ ÿÿÿ.ÿGÿWÿSÿCÿ*ÿ%ÿ;ÿrÿ¶ÿöÿ.a‰±ÌÛÙã}X8  '("ùÿøÿôÿäÿÈÿžÿqÿJÿÿñþÇþªþ£þ¶þÝþÿ5ÿHÿNÿKÿ[ÿ{ÿªÿâÿR‹¾ëþæ¹mYOR]p‚ŠfA! ûÿóÿÚÿµÿ‡ÿYÿ,ÿÿ×þ´þ¤þ§þÃþæþÿÿÿ ÿÿ1ÿnÿ¾ÿ\šÈëüÿìÆžzffp‡¢ÀÕÞѶgJ4"Öÿžÿcÿ,ÿüþÒþ¨þ‰þ€þ”þ¾þéþ ÿÿÿ ÿÿ0ÿbÿ©ÿøÿCˆÁñåÐÁ½¿ÇØìüöÛ¸™‚s]<Åÿ€ÿ9ÿðþ§þiþ5þ"þ1þZþ‰þ²þËþ×þåþÿþ+ÿgÿ±ÿûÿ>~ªÉÓ˰”ˆŠ¢Ð<h€x^2ùͱ£›‹h3øÿºÿuÿ'ÿàþ˜þdþJþFþQþcþgþcþ\þ_þ}þ¸þÿcÿÃÿ uºèóÌžxac²î>E5òÚÕÖÓÆŸg'Þÿ™ÿMÿÿÐþ®þ£þ«þ¹þÄþ¼þ¦þ‘þƒþŠþ¯þçþ+ÿuÿÁÿÿÿ6W_O7# 4]žé-f„„h2ýÖ»«žŠkDâÿÿPÿÿþ¹þŽþ€þ†þšþ¨þªþ¥þ¬þ¹þØþ ÿNÿ“ÿÜÿDehS$êÿ·ÿ—ÿ™ÿ¹ÿöÿC“Ö  à«r/çÿ˜ÿMÿ ÿÝþÆþÅþÎþÒþÅþ¯þ–þ‚þ~þ›þÌþÿcÿ·ÿDr„€c8øÿöÿ*Wƒ¢¯¨˜’£¼Íɰ‡QÃÿwÿ-ÿóþÐþÍþÛþðþÿþÿüþöþöþÿÿ9ÿfÿ”ÿºÿÝÿóÿÿÿóÿçÿÐÿ¼ÿ¸ÿÈÿñÿ*nªÒáÕ¯ƒ\OWk‰ƒv^5Äÿ‚ÿEÿÿÿÿþúþçþÓþ½þ¬þªþ»þêþ-ÿ~ÿÐÿTplKÏÿ“ÿoÿlÿ”ÿ×ÿ,y´ÍǤ}ZD?:2$ýÿäÿÆÿ¡ÿwÿ\ÿNÿPÿ_ÿuÿ‡ÿ‰ÿ{ÿlÿWÿMÿUÿgÿ„ÿ­ÿØÿúÿ üÿÞÿ½ÿ¢ÿÿ‘ÿ¬ÿÙÿc™¹Á±˜‚x~‚~kJðÿÄÿ•ÿcÿ3ÿÿüþùþÿÿÿÿÿ(ÿ@ÿeÿ£ÿïÿ=ˆÇêóÚ¥VµÿvÿXÿ]ÿ„ÿ¿ÿ Mvƒƒztx}‚|jI&Þÿ¹ÿ“ÿrÿgÿhÿ}ÿ‘ÿ™ÿ•ÿŽÿzÿhÿ_ÿgÿ‚ÿ²ÿóÿ?ˆÄîùèÄ“^5&DmœŒlG+#4KO>$üÿÐÿœÿkÿ:ÿÿÿ'ÿHÿsÿ”ÿ«ÿ¸ÿÀÿÊÿ×ÿïÿ6d•¾Îͺ˜nK9=_›á%NR.î£\.ýÿõÿßÿÄÿ¥ÿ{ÿMÿ%ÿÿÿÿ5ÿLÿ_ÿyÿ–ÿ¾ÿóÿ+e×Ö—Sïÿéÿ V¬MoiJé¼—rKóÿÊÿ¡ÿvÿIÿÿøþãþãþõþÿ6ÿKÿcÿ{ÿ˜ÿ·ÿßÿ E}½î&!Ó™iJHižâ0,æ¹’€siXC*áÿ±ÿ}ÿCÿÿþþ÷þÿÿÿ!ÿ(ÿ6ÿRÿ{ÿ¹ÿU©ñ)KN8€F+1[™ß5B9ðÒ´Žb+ìÿ²ÿtÿ8ÿÿþØþ»þºþÍþíþÿ,ÿ=ÿJÿVÿkÿ‰ÿ³ÿéÿ)k²è ûÔ¤|huœÐýèÅ«›š’‰v]5úÿ¸ÿgÿÿÃþŠþqþsþ‹þ±þÖþÿþ$ÿJÿqÿšÿÃÿôÿ&[‰¬¿¼§~R1"7l¶Ab`@⸙„qY;éÿ±ÿrÿ.ÿòþÁþœþ‹þ†þ„þ†þ‡þ’þ®þÕþ ÿPÿ¥ÿúÿK޾ÜÚÁ›c*ûÿãÿìÿKˆ»ÝéåßϾ´§–~_7ÍÿŠÿFÿ ÿáþÂþ°þ¯þ°þ«þ­þ«þ¬þ¹þÒþûþ1ÿlÿ³ÿøÿ6b~†xZ?+2S„»êñϨ\8íÿØÿ»ÿ˜ÿxÿKÿÿõþÛþÎþÎþÖþàþçþìþ÷þÿÿ7ÿYÿ„ÿ³ÿáÿÜÿ³ÿÿtÿwÿ¢ÿñÿT´2D5úظ˜qDàÿ¥ÿkÿ/ÿûþÐþ±þ£þžþ¡þ£þªþ­þ³þÃþÜþÿ8ÿsÿ¬ÿâÿ '681òÿÆÿŸÿŠÿŠÿªÿÙÿCl‘šžœ–‹}iF×ÿ‰ÿ9ÿìþ®þ‡þsþlþlþxþþ°þÚþÿKÿÿÉÿýÿ 64!Úÿ¨ÿ~ÿ`ÿUÿjÿŸÿëÿ>‚®À¼¦ŠjD#þÿÞÿÁÿ°ÿ¡ÿÿ{ÿ_ÿ9ÿÿþþäþÐþÂþ²þ¦þþžþ´þÚþÿRÿ”ÿÔÿ ,BK>"ûÿÌÿ¨ÿ—ÿ ÿ½ÿïÿ'Pk‡ŽŒ}b=Ùÿžÿaÿ!ÿêþºþ—þ‹þŠþ•þŸþªþ¼þÐþñþÿGÿzÿ«ÿÕÿöÿ þÿåÿÈÿªÿ˜ÿÿ™ÿ½ÿñÿ.a‹£®¯¯­ “‡ugR6 Ïÿÿ0ÿâþ¢þvþ_þOþQþ_þqþþÃþÿMÿ–ÿÙÿ /AC5ùÿ×ÿµÿÿœÿµÿàÿS€— ›™ƒ~uldXO<óÿÁÿ‰ÿSÿ+ÿ ÿòþÞþÌþ¼þ±þ´þÄþâþ ÿEÿzÿ¯ÿ×ÿòÿûÿóÿßÿÈÿ±ÿ¥ÿ©ÿÄÿîÿB`qoigaca`]]`_R1Èÿ‹ÿVÿ.ÿ ÿöþêþãþïþÿ&ÿSÿ‹ÿ½ÿåÿ æÿËÿ±ÿ”ÿ~ÿvÿ|ÿ˜ÿÆÿÿÿ<gˆ‡{iW:ÿÿëÿâÿäÿìÿíÿåÿÓÿ¶ÿ˜ÿÿiÿWÿDÿ1ÿÿÿÿ;ÿpÿ­ÿóÿ2awpP#îÿµÿ~ÿYÿEÿDÿaÿ’ÿÔÿFm¤¼ËÐÍ·^*÷ÿÆÿŒÿOÿÿóþÙþÒþÞþóþÿ,ÿLÿoÿšÿÇÿÿÿ6i”®³ªg: Üÿ´ÿžÿ¡ÿ»ÿÝÿ*=?;67BM^hs†„qG ËÿŠÿKÿÿýþáþÉþ¾þÂþÛþÿFÿ™ÿñÿ>‡¾×ÙȨ€R%öÿ#S}œ³ººµ¯¥‘pH#íÿÝÿÈÿ§ÿ…ÿdÿOÿGÿCÿEÿLÿQÿQÿ[ÿnÿŠÿ®ÿáÿEj~wgK* îÿßÿÛÿêÿ 7l”±ÁÍáô á°Mæÿ±ÿzÿFÿÿüþçþÞþÜþâþíþÿ:ÿ{ÿËÿ"g™·¹¡zNïÿÕÿÊÿÑÿîÿKv‘–‰‚‰œªµ¿ËÌȺ™d$ÞÿŸÿkÿKÿ3ÿÿÿôþíþ÷þÿOÿ›ÿîÿB‚¬½³”i0ùÿÉÿªÿ¥ÿºÿçÿMv£¹ËÛäæàϽ¯•{T$ðÿ½ÿ’ÿqÿaÿ]ÿZÿQÿKÿFÿPÿnÿžÿÙÿV†¦«™xR$ÿÿåÿãÿñÿ8Viha\dm~’ž££¤¦£™~V!êÿ¸ÿ‰ÿkÿRÿ=ÿ5ÿ;ÿOÿzÿ°ÿóÿ0i•¦¢‹c.õÿÄÿ¦ÿœÿ°ÿßÿfœ¿ÊÎÌÈÆ¿¸¤‡lQ5èÿËÿ¯ÿ’ÿÿxÿyÿwÿrÿpÿvÿ†ÿ­ÿåÿ$bšÄÕίCÍÿ¬ÿ¤ÿ´ÿÔÿ,Uiikox‰Ÿ²¼Ãľ°’\Êÿ}ÿ=ÿ ÿõþîþòþÿÿ8ÿdÿŸÿäÿ3{¸àíÞ¾‰KêÿÓÿÕÿíÿ9Wlomfbflqwz{ƒ„}mNæÿ©ÿqÿFÿ)ÿÿÿÿ$ÿAÿkÿ¡ÿâÿ#c•¶Ãµ‘e/ýÿØÿÉÿÐÿôÿ"RyŒ”ˆ‹‘“‰}p_J7õÿÈÿ™ÿmÿDÿ(ÿÿÿÿÿ!ÿGÿ‚ÿÈÿWެ­’oCáÿ»ÿªÿ¯ÿÇÿðÿDZgipx†—¨µ»¿À³xC·ÿcÿÿéþÈþ¸þ¹þÉþãþ ÿCÿ‰ÿßÿ7‰Éñõâ¬hÐÿ—ÿ}ÿÿŸÿÍÿ-CJJHLU[fr‹•˜”}TÝÿœÿZÿ)ÿÿïþáþÞþæþúþÿXÿŸÿðÿ@†¸ÎÉ«v:ÙÿÃÿÎÿéÿ0BGEBCPeu†’„r]:âÿ­ÿpÿ?ÿÿÿþðþñþÿÿ:ÿjÿ ÿßÿHl}vaAîÿÌÿ·ÿ¶ÿÈÿåÿ)@LLQYalzƒˆˆ‰„qP(÷ÿÄÿ’ÿcÿ;ÿ#ÿÿÿÿ$ÿ=ÿeÿ˜ÿÔÿEjxnQ#øÿÌÿ°ÿªÿ½ÿáÿ.DI:1,8QqŒ¥µ»º³›zKÚÿ§ÿ}ÿXÿ?ÿ.ÿ0ÿ8ÿHÿeÿŽÿ¿ÿóÿ0e‘¦¥‹[Ûÿ£ÿ…ÿ|ÿ–ÿ½ÿêÿ  ?`{³¾¿¹¢~Qéÿ³ÿ€ÿTÿ<ÿ1ÿ2ÿBÿ`ÿŠÿ¸ÿìÿNw“œ“{W(ûÿÖÿ¼ÿ¼ÿÎÿïÿ+3+øÿôÿýÿ"=RennV7êÿÄÿ ÿ€ÿiÿ]ÿXÿ_ÿvÿšÿÏÿ E~¬À¾Ÿj,ëÿ¹ÿœÿ˜ÿµÿâÿB\c[VSXdq…ˆ‰{bFïÿÂÿ™ÿvÿUÿ;ÿ.ÿ)ÿ/ÿHÿkÿ•ÿÏÿOÂæóçÄŠBûÿÂÿžÿÿ²ÿÜÿ 3DD;55AVr©ÁÓÕɬ}CÇÿ“ÿiÿDÿ)ÿÿÿ/ÿQÿ~ÿ·ÿõÿ5s©ÒÞÚ¾NÞÿËÿÐÿïÿB]mi[NGMWh‰ªÆÝéæÍ g(îÿ¼ÿÿvÿdÿ]ÿcÿsÿ“ÿ»ÿòÿ3q¦ÒèéÓ£l0üÿØÿÊÿ×ÿ÷ÿ5EGFJNYp…›±ÅÔäèãÍ­Š[2Øÿ¶ÿÿÿ’ÿ£ÿÂÿåÿJ}ªÏÞáͧq9 åÿÙÿáÿüÿ'*"'<]ƒ«Øùã±vD Ýÿ¼ÿ©ÿœÿ¡ÿµÿÕÿ8u®áܤ`äÿÍÿÔÿêÿ!0%÷ÿðÿøÿ'Ly£Ã××ȬˆbAòÿâÿÔÿËÿÐÿàÿüÿ)b Ø ݨi5þÿþÿ +-# %9TfnskY8÷ÿÙÿÄÿ·ÿ»ÿËÿèÿ 6b´ÕéñíØ¹Z#øÿäÿãÿúÿ<OSE.üÿ&;MRM7ûÿÛÿ½ÿ¥ÿ’ÿŠÿŽÿ‘ÿ¢ÿ»ÿãÿNÉ$5)È.äÿ­ÿœÿªÿÇÿôÿ <IHC:- %1@HF4ðÿÎÿ¬ÿ‡ÿhÿSÿIÿMÿYÿhÿ„ÿ°ÿæÿ.xÁü*94 Î6ïÿ¿ÿ¥ÿ¦ÿºÿÎÿÝÿäÿâÿèÿîÿõÿ(:Rl{~pS&ñÿºÿ‚ÿMÿ#ÿ ÿ ÿÿ6ÿZÿ„ÿµÿñÿ-l£×ú  õÀ8öÿÈÿ³ÿ¸ÿËÿßÿëÿíÿåÿÛÿÕÿÐÿÐÿÙÿèÿýÿ7LUH4êÿ½ÿ’ÿfÿCÿ&ÿÿÿ"ÿ9ÿ`ÿ—ÿÖÿ"o²ç ÙœS Íÿ©ÿœÿ¢ÿ¯ÿÀÿÊÿ×ÿáÿíÿøÿ(7Tl~nIâÿ¦ÿkÿ>ÿÿÿÿ ÿÿ-ÿJÿsÿªÿêÿ5~½ðþÔ™PÙÿÀÿ¹ÿ½ÿÀÿ¿ÿ½ÿ±ÿ«ÿ±ÿ»ÿÄÿÔÿëÿ(Mo‚†z\/÷ÿ»ÿ{ÿGÿÿÿýþÿ"ÿHÿ|ÿ¶ÿõÿ9z½ï ÖšUëÿÚÿÚÿåÿøÿýÿóÿçÿÛÿÒÿÍÿÈÿÏÿçÿ ,IYYG*Õÿ§ÿ{ÿWÿ6ÿ ÿÿ$ÿ<ÿaÿ•ÿÍÿY˜Êðß­r2çÿÞÿêÿúÿ  ýÿ1SiqfM'þÿÑÿ£ÿyÿVÿ=ÿ,ÿ'ÿ)ÿ>ÿ`ÿ‘ÿÏÿ]¡ÖöýêÇŒKâÿÐÿÊÿ×ÿãÿóÿ úÿþÿ+MewzjMæÿ©ÿnÿ9ÿÿÿÿÿ3ÿeÿŸÿãÿ+s²äÔ™XìÿÏÿÆÿÌÿÔÿØÿÛÿãÿîÿöÿ "5JctubL+Þÿ¶ÿ•ÿyÿfÿ\ÿVÿ\ÿlÿ‡ÿ¬ÿÑÿÿÿ-Z‡ ²² zLùÿèÿíÿöÿ ÷ÿïÿêÿçÿèÿòÿ9XkshMìÿ´ÿ|ÿNÿ+ÿÿÿ"ÿ=ÿfÿ›ÿÖÿR‡·ÍÓ˯‚EÔÿ²ÿ¨ÿ¬ÿ¹ÿÃÿÐÿÚÿãÿïÿûÿ&>Wp€€oH×ÿ˜ÿXÿ#ÿüþìþëþ÷þÿ@ÿvÿ¯ÿëÿ.k¢ÐêñÛ¬g#æÿºÿ¥ÿ¢ÿ¦ÿ®ÿµÿ¾ÿÃÿËÿÝÿïÿþÿ$?^y‘›„\,ðÿ­ÿsÿ>ÿÿõþæþîþ ÿ6ÿmÿ«ÿîÿ/h—·ÉÄ«€E ßÿÄÿ´ÿ³ÿ²ÿ´ÿ¯ÿ­ÿ¯ÿ·ÿ½ÿÈÿÙÿéÿ$LpŒ›ž”wN èÿ°ÿyÿOÿ+ÿÿÿ'ÿIÿuÿ«ÿÜÿHvž»Ä·“e5 ïÿÜÿÒÿÌÿÈÿÉÿÑÿÛÿîÿûÿ .@SXZUL8 ìÿÕÿ¼ÿ¨ÿ™ÿ’ÿ—ÿ¦ÿÁÿÞÿ-U|³¸©…QïÿÒÿÂÿÃÿÊÿÑÿÖÿÚÿåÿïÿ5On¦²¯¡‡d1ýÿÈÿ˜ÿpÿSÿBÿBÿOÿsÿ§ÿåÿ&d›Ëï ñÁ„EéÿËÿ½ÿ·ÿ³ÿ´ÿ·ÿÂÿÎÿÞÿïÿýÿ2Mn‹™¡˜ŒyaEõÿÌÿ§ÿ‹ÿyÿvÿƒÿ£ÿÎÿþÿ/^…¦ÃÓÖǧ€[=/&ûÿùÿóÿñÿõÿ2Sp‚‰‚pQ-Øÿ³ÿ—ÿ‡ÿ†ÿ’ÿ²ÿÝÿEv™¯ÂËÌç~Møÿéÿêÿõÿ%'%"+BZm‹‡u[8 Úÿ¬ÿ…ÿfÿ\ÿdÿ…ÿ¼ÿüÿ>€¶ÚööИXêÿÐÿÆÿÈÿÒÿÝÿìÿ!)2,06DTcqw{rfN+Þÿ¯ÿ‡ÿhÿYÿ_ÿÿ½ÿLÆíöÑj:úÿæÿÙÿÐÿÌÿÐÿÒÿÙÿãÿîÿûÿ*Ih„•š–„oK"üÿÚÿ¶ÿ‘ÿ|ÿpÿrÿ„ÿ©ÿäÿ ^•¿àøêÂŒT* õÿèÿáÿâÿäÿâÿÝÿÚÿÒÿÍÿÐÿÜÿùÿ@^t€ƒxbH%ýÿÕÿ«ÿŠÿoÿ[ÿiÿ‚ÿ·ÿùÿ>x°Üý$Ú§rH# üÿúÿôÿôÿòÿðÿìÿàÿàÿêÿüÿA`x„€oS*ÿÿÔÿ©ÿ†ÿhÿNÿ>ÿCÿXÿ‰ÿÈÿ_˜ÁÛéíéÛÅ©uaTMD6)# ùÿ÷ÿ÷ÿ9Tm~‰„mO ëÿ³ÿÿPÿ%ÿ ÿÿÿGÿŽÿÚÿ/{·çûÕ§^IABAA?4+ ýÿ8Ys†Šˆz]9àÿ­ÿÿXÿ4ÿÿ ÿÿ9ÿhÿ¢ÿØÿ =h•¸Ç¾©‰lQ=435;?AC@60.6G[ipeYM8# úÿãÿÏÿ¶ÿ›ÿ}ÿjÿeÿqÿ‹ÿ¬ÿÔÿøÿ+AS_\N;# ûÿëÿàÿÞÿäÿóÿ*246D[u‘°ÅÌůˆRÙÿ£ÿsÿLÿ1ÿ$ÿ*ÿHÿuÿ¦ÿßÿ;]q~„vfJ1òÿèÿØÿÍÿ¿ÿµÿ¯ÿ´ÿ¹ÿ¹ÿÃÿÒÿîÿ=b€—¥§œ…hEæÿ¶ÿŒÿiÿSÿLÿZÿzÿ©ÿÛÿ1Q`f]K'ýÿâÿÎÿËÿÓÿæÿûÿçÿÉÿµÿ¬ÿ¶ÿÐÿîÿ-FUUM=$ êÿÉÿ¢ÿÿcÿXÿaÿ€ÿ±ÿèÿ#Vy—”_2 âÿÀÿ­ÿ ÿ¡ÿ¬ÿ¾ÿÔÿêÿöÿúÿøÿêÿÜÿ×ÿÝÿíÿÿÿ$*(ëÿÐÿ²ÿ–ÿÿdÿNÿCÿBÿOÿoÿšÿËÿüÿ&Gbx|wcAöÿÑÿ´ÿ ÿ›ÿÿ«ÿ»ÿËÿÛÿåÿèÿêÿåÿæÿêÿúÿåÿÈÿ¥ÿ{ÿRÿ/ÿÿÿÿÿHÿ‚ÿ»ÿðÿ"G]lndI* ëÿÔÿÀÿ²ÿ¤ÿ˜ÿ“ÿ‘ÿÿ˜ÿžÿ§ÿµÿÈÿåÿÿÿ*22(áÿÄÿ«ÿÿnÿPÿ2ÿ!ÿÿ&ÿEÿrÿ¢ÿÎÿïÿ"&( öÿâÿÐÿÂÿ¶ÿ¬ÿ¦ÿ¢ÿœÿ ÿ£ÿŸÿŸÿ£ÿ¬ÿºÿÕÿòÿ'53' èÿÁÿšÿrÿUÿ;ÿ(ÿÿÿ$ÿ=ÿgÿœÿÔÿ,IVZS<üÿÚÿÀÿ±ÿ§ÿŸÿ™ÿ—ÿžÿ¡ÿ£ÿ§ÿ£ÿŸÿ¢ÿªÿ¾ÿßÿ/OkvjM(ôÿºÿ„ÿPÿ%ÿÿêþíþþþ%ÿ\ÿœÿàÿ:Vouk\<ùÿÞÿÍÿ¼ÿ³ÿ©ÿ£ÿžÿ ÿ¢ÿžÿšÿžÿžÿ¥ÿµÿÊÿæÿ#>UXM8ðÿÇÿ•ÿhÿCÿ#ÿÿÿ7ÿdÿ˜ÿÌÿûÿ#AS^\L7ëÿÞÿØÿÕÿÖÿÜÿÚÿÓÿÊÿ¹ÿ©ÿ›ÿ•ÿ–ÿ¥ÿ¿ÿÛÿýÿ2HNA0îÿÆÿ ÿxÿ[ÿGÿEÿSÿqÿ›ÿÈÿðÿ #2;:1ðÿßÿÕÿÒÿÕÿßÿìÿøÿûÿôÿëÿíÿíÿñÿ÷ÿ ôÿëÿæÿáÿÝÿÑÿÃÿ°ÿ ÿ˜ÿ ÿ°ÿÊÿèÿÿÿ*=EG=& ðÿÙÿÊÿÆÿÅÿÅÿÎÿÖÿÛÿÚÿØÿ×ÿÛÿÞÿèÿ÷ÿ "8KZ\N8÷ÿÏÿ¬ÿŽÿxÿhÿfÿnÿ„ÿ¡ÿÊÿåÿ "4@LMI=&öÿáÿÙÿÒÿËÿÐÿÔÿÕÿÖÿÔÿÒÿÎÿÈÿÎÿÛÿìÿ-:><,úÿáÿÈÿ²ÿŸÿ‹ÿ‚ÿ…ÿ–ÿ³ÿÚÿ'AW^^]O;!÷ÿÐÿ´ÿ›ÿÿŒÿ’ÿ¤ÿ·ÿÈÿÛÿëÿóÿõÿüÿ %/41%õÿÕÿ»ÿ¤ÿŽÿÿsÿrÿzÿ–ÿ¹ÿèÿ>XeifXE+òÿØÿÆÿ»ÿ¶ÿ´ÿ¹ÿºÿ¾ÿ¼ÿ¾ÿ¾ÿÃÿÉÿØÿêÿùÿ %065)ðÿÐÿ±ÿ’ÿ{ÿeÿWÿNÿYÿrÿ•ÿÈÿýÿ+Vz’—ƒf6Ðÿ¦ÿƒÿnÿeÿnÿ}ÿ‘ÿ§ÿ¹ÿÊÿÜÿìÿ#8GVYYUD( åÿÀÿ™ÿyÿ\ÿEÿ1ÿ-ÿ=ÿWÿ|ÿ¤ÿÑÿûÿ!>RajdM2õÿÕÿÃÿ°ÿ¦ÿŸÿšÿÿ‹ÿ†ÿˆÿÿ˜ÿ«ÿÄÿàÿ7MWQ>ûÿÖÿ¸ÿšÿÿrÿjÿnÿ~ÿ–ÿ±ÿËÿÞÿçÿëÿðÿõÿýÿùÿñÿãÿÓÿÇÿ¹ÿ·ÿ´ÿ¹ÿ¹ÿµÿ®ÿ¦ÿ¢ÿ¡ÿ«ÿ¸ÿÇÿÚÿõÿ '33% çÿ¿ÿ›ÿzÿZÿAÿ8ÿ@ÿWÿ}ÿ°ÿÞÿ0880 úÿáÿÈÿ¯ÿ˜ÿ…ÿsÿdÿgÿlÿsÿwÿ€ÿŒÿšÿ°ÿÅÿÝÿïÿÿÿîÿÐÿ¹ÿ¤ÿÿ|ÿjÿ_ÿ`ÿlÿ„ÿ¨ÿÊÿêÿòÿáÿÏÿ¿ÿ³ÿªÿ«ÿ±ÿ³ÿ²ÿ¨ÿ›ÿ‘ÿ‰ÿŒÿ“ÿ£ÿ±ÿÃÿØÿèÿ÷ÿÿÿýÿíÿÒÿºÿ ÿƒÿpÿ`ÿYÿ^ÿjÿÿ£ÿÊÿîÿ &--' ñÿÛÿÄÿ«ÿ˜ÿ’ÿŒÿ—ÿ«ÿÁÿÍÿÒÿÒÿÐÿÍÿÊÿÇÿÈÿÉÿÎÿØÿÞÿãÿàÿÓÿ½ÿ¥ÿŠÿsÿ_ÿSÿNÿNÿZÿvÿ’ÿ²ÿÓÿîÿûÿ ýÿöÿíÿáÿØÿÏÿÃÿ¹ÿªÿ¤ÿ¢ÿ¡ÿ¨ÿ±ÿ¹ÿ¿ÿÊÿÜÿìÿýÿ !),% èÿ¸ÿŒÿdÿ@ÿ&ÿÿÿÿ6ÿVÿÿÂÿôÿ ?KK;%æÿÅÿ©ÿ•ÿˆÿ|ÿrÿpÿyÿ†ÿ”ÿ£ÿ«ÿ²ÿ¾ÿÌÿàÿôÿ*064+üÿÙÿ²ÿÿgÿGÿ/ÿÿÿÿ2ÿVÿ…ÿ¹ÿßÿ,.%æÿÌÿ³ÿÿ‡ÿ|ÿtÿtÿuÿÿÿÿ’ÿ›ÿ§ÿ¼ÿÐÿæÿþÿ&6=5ýÿÚÿ¶ÿ—ÿzÿbÿUÿKÿKÿUÿlÿŠÿ®ÿËÿäÿôÿûÿùÿëÿÜÿÌÿºÿªÿšÿŽÿ„ÿ€ÿÿƒÿ„ÿ…ÿŒÿÿ–ÿŸÿ²ÿÆÿÜÿôÿ $14,óÿÃÿÿiÿGÿ.ÿÿÿ$ÿ?ÿdÿ˜ÿÉÿöÿ;ID9%éÿÌÿ¯ÿ˜ÿ~ÿmÿaÿbÿgÿtÿˆÿ“ÿ¥ÿ²ÿÅÿÚÿìÿ"" ñÿÐÿ­ÿˆÿlÿRÿCÿ9ÿ5ÿ9ÿLÿfÿŒÿ³ÿÙÿûÿ  ÷ÿïÿíÿçÿÞÿÒÿÆÿµÿ­ÿ¤ÿœÿ•ÿšÿ¡ÿ²ÿÏÿíÿ %@UebXC!ùÿÌÿ¡ÿ~ÿ[ÿIÿ=ÿ;ÿEÿ`ÿ†ÿ³ÿßÿ *-%òÿáÿÚÿÙÿØÿÙÿÝÿåÿèÿëÿïÿæÿ×ÿÍÿÆÿÇÿËÿÙÿèÿ5ISL:!åÿÅÿªÿŒÿtÿiÿfÿpÿˆÿ¦ÿÆÿæÿ ùÿäÿÓÿÂÿ»ÿºÿ»ÿÁÿÍÿÔÿÛÿäÿíÿøÿ %1=DKNH?% èÿÈÿ©ÿ•ÿ‚ÿ|ÿyÿ~ÿ‰ÿ¡ÿ¼ÿáÿ%;BB6ùÿÚÿ¾ÿ¥ÿ“ÿŠÿ‡ÿÿ™ÿªÿ½ÿËÿÞÿëÿùÿ ,CZsˆ˜œwPéÿµÿˆÿeÿLÿ@ÿAÿTÿoÿ•ÿÂÿñÿ4NWSF6 øÿãÿÎÿ»ÿ¬ÿžÿ”ÿÿÿ‘ÿ—ÿ¡ÿ±ÿÈÿëÿ6\~›ªªž~U+üÿÔÿ±ÿ–ÿ}ÿmÿgÿhÿtÿˆÿ¤ÿÈÿçÿ #ðÿæÿáÿÝÿ×ÿ×ÿÖÿÔÿÑÿÌÿÀÿ¶ÿ±ÿ·ÿ¿ÿÑÿêÿ +Lhy|lN%õÿÉÿ ÿ}ÿeÿ`ÿbÿuÿ”ÿ»ÿâÿ%9=4"áÿ»ÿ¢ÿ‹ÿƒÿƒÿ‹ÿ™ÿ°ÿÂÿÝÿëÿõÿöÿ÷ÿõÿîÿñÿõÿþÿ 7JPM9÷ÿÎÿ¬ÿÿuÿeÿYÿYÿaÿxÿ”ÿ®ÿÎÿñÿ !)"üÿåÿÉÿ·ÿ§ÿ—ÿÿ’ÿ”ÿ›ÿ¨ÿ·ÿ¿ÿÇÿÎÿÔÿäÿöÿ.Lg}ˆƒi@Ùÿ«ÿ„ÿaÿJÿ:ÿ1ÿ6ÿJÿgÿŽÿµÿàÿ+(åÿ½ÿ¡ÿ‹ÿ‚ÿ€ÿƒÿŽÿ•ÿ¤ÿ®ÿ®ÿ³ÿµÿ¾ÿÎÿãÿýÿ9[u‰ŒsHèÿºÿ•ÿ}ÿoÿhÿeÿiÿrÿ|ÿŒÿÿ°ÿÇÿÙÿëÿòÿòÿèÿÙÿÊÿ¶ÿ¢ÿ’ÿ…ÿ„ÿŠÿ•ÿ¥ÿ³ÿÁÿÃÿÉÿÉÿÎÿÛÿéÿ@^u€x_6Ùÿ²ÿŽÿuÿoÿqÿ€ÿ™ÿ²ÿÒÿðÿæÿÆÿ¤ÿ‰ÿqÿgÿ`ÿcÿlÿ~ÿÿ¥ÿ»ÿÊÿÐÿØÿ×ÿÞÿæÿøÿ+Kc}ƒ~gBÙÿ¥ÿuÿQÿ?ÿ7ÿ@ÿOÿmÿšÿÎÿÿÿ,N]dT6 Þÿ¯ÿ„ÿbÿLÿBÿBÿLÿ[ÿoÿÿÿ™ÿ§ÿ¶ÿÌÿæÿ/Roœž–vO ìÿ¶ÿŒÿeÿMÿ6ÿ2ÿ9ÿKÿcÿŠÿµÿæÿ8QZS=úÿÖÿµÿ›ÿÿ†ÿ†ÿŽÿ“ÿ—ÿšÿ˜ÿ—ÿšÿªÿÀÿÞÿ0Wv††rQ&ôÿÉÿ¤ÿ‰ÿsÿjÿgÿhÿxÿ‘ÿªÿÅÿÝÿðÿþÿ òÿâÿÇÿ´ÿ¨ÿ¤ÿ¤ÿ¬ÿ¿ÿ×ÿìÿ ûÿôÿðÿñÿúÿ*F]gdX9åÿ»ÿ˜ÿwÿeÿ[ÿ]ÿiÿ}ÿ ÿÂÿàÿ%.+êÿÓÿ¹ÿ©ÿžÿšÿ™ÿ£ÿ±ÿÄÿÑÿÞÿéÿîÿôÿ8_ƒ¢·Ä¾£{EÃÿ‰ÿYÿ6ÿ"ÿ"ÿ9ÿZÿ‡ÿµÿàÿ 070îÿÔÿÀÿ³ÿ¬ÿ¯ÿ¹ÿÃÿÑÿáÿíÿðÿðÿçÿèÿçÿôÿ *S~¢ÃÑȯŠSØÿ›ÿiÿCÿ/ÿ,ÿ9ÿTÿ{ÿ¥ÿÏÿòÿ " òÿÒÿ³ÿœÿÿƒÿ‚ÿˆÿ›ÿµÿÕÿöÿ 0Ln“²Î×ЭI Ìÿ”ÿfÿCÿ6ÿ5ÿAÿbÿŒÿ¶ÿÞÿ$37.ÿÿäÿÆÿ¦ÿ˜ÿŽÿ‘ÿ–ÿ¯ÿÉÿâÿýÿ&1Fb‚§ÇßëàÆœd"âÿ¥ÿvÿXÿKÿVÿpÿ“ÿ¸ÿåÿ -30èÿÅÿ¥ÿ‘ÿ|ÿyÿ{ÿÿ«ÿÐÿóÿ+>LYo‡Ÿ¼Ùò 콉MÕÿ™ÿiÿQÿNÿ[ÿ‚ÿ¯ÿäÿBcu‚€rZ<ýÿÚÿ¾ÿ¥ÿ›ÿ ÿ¬ÿ»ÿÑÿæÿõÿ$Kq×@g†…qMßZ"òÿÏÿ¸ÿ°ÿ°ÿ¼ÿÑÿèÿûÿ!,-)$$$+3=DIJOOHB39cœÕIs‡ŠoE ˉP!ÿÿïÿôÿ#Gi„™š”€c:ôÿ×ÿ¿ÿºÿÇÿãÿ-Us‡’‹—­ËñCYko`@Ú£i:üÿûÿ-U€©ÁÏÑ®jD÷ÿßÿÓÿÓÿÞÿøÿ5Pbjou}’·à<`yyd@å²€T3#7]‡¯ÊÜäßʵgE" ûÿõÿùÿ.BQV]hv—¾ê@\ihP/É’^34]ˆ¯ËÞàׯ¬ŒnN1 ýÿýÿ !'*3>Wv¡Íý(HWYM.И_(ëÿßÿçÿÿÿ&Mw›µ¿¾°–vW6øÿòÿüÿ "3<@4! .X“Ô;UXAåžX Ïÿ ÿˆÿ{ÿÿ·ÿðÿ2s¦ÆÔζ’f8ìÿÓÿÇÿÇÿÑÿäÿüÿ!)+' +Fq§ß9GD-Õ‘K¾ÿÿZÿDÿEÿcÿ’ÿÏÿGvœ¬ª›{V*éÿ×ÿÓÿÓÿÞÿïÿøÿÿÿùÿüÿ (R‚¸ì).ÑK¿ÿ„ÿ\ÿHÿKÿaÿ…ÿµÿáÿ .?JHD5 ÷ÿïÿäÿéÿðÿúÿ   ;`†­ÉÖ×˱“kBãÿºÿœÿÿuÿyÿ‹ÿ£ÿÃÿÝÿðÿüÿüÿïÿÝÿÍÿºÿ©ÿÿ›ÿ–ÿ¡ÿ¹ÿÔÿîÿ .JqÏîüû仈JÍÿ—ÿlÿKÿ8ÿ9ÿGÿfÿ‘ÿ¼ÿàÿ þÿáÿ¾ÿ—ÿlÿSÿ>ÿ9ÿ@ÿXÿwÿ˜ÿ³ÿÇÿÐÿÚÿÝÿãÿçÿøÿ>qªÜþöК^Ôÿ”ÿ\ÿ0ÿÿÿ'ÿCÿhÿ‘ÿ»ÿÕÿäÿáÿÑÿ¼ÿšÿpÿEÿ&ÿÿÿÿÿEÿpÿœÿÁÿÙÿæÿìÿìÿìÿõÿ #Q«ÐèíáÈŸj*éÿ©ÿmÿ<ÿ!ÿÿ#ÿ@ÿgÿ’ÿ¶ÿÌÿÚÿÖÿÃÿ¤ÿ{ÿMÿÿùþÝþÊþÇþÐþîþÿ:ÿ`ÿ|ÿ’ÿ§ÿ·ÿÏÿèÿ@w¨ÔíñàÆ¡l8Íÿ–ÿiÿLÿ<ÿ:ÿNÿkÿŽÿ³ÿ×ÿïÿöÿìÿ×ÿ°ÿÿHÿÿæþÃþ´þ°þ»þÔþòþ ÿ%ÿ7ÿJÿaÿxÿ˜ÿÅÿ÷ÿ,d—¿×ÚÒ¶b.óÿ¹ÿ†ÿ_ÿBÿ6ÿ@ÿWÿwÿ™ÿ¸ÿÕÿâÿåÿßÿÒÿ¶ÿ’ÿkÿ?ÿÿøþßþÐþÍþÑþØþàþãþêþôþÿ"ÿSÿ“ÿÛÿ(q¯ØëäÌ¡n/ðÿ¶ÿÿTÿ<ÿ0ÿ6ÿMÿmÿ•ÿ¸ÿÚÿñÿúÿôÿãÿÂÿœÿqÿFÿ!ÿÿøþñþöþ ÿÿÿ!ÿÿÿÿÿ ÿ"ÿRÿŒÿÕÿ[‹©¶°š}Oéÿ±ÿ‚ÿ^ÿJÿEÿRÿpÿŽÿµÿØÿíÿùÿóÿÛÿ¿ÿ“ÿ`ÿ9ÿÿÿÿ ÿÿ2ÿEÿOÿSÿLÿEÿ=ÿ8ÿAÿWÿyÿ¥ÿÚÿ?d{qU6æÿ¸ÿÿxÿkÿhÿqÿ‡ÿ¨ÿÈÿèÿÿÿ þÿàÿºÿŠÿVÿ(ÿÿêþâþêþÿ$ÿCÿ[ÿjÿqÿpÿgÿgÿpÿÿ°ÿÛÿ7\u|weL)Úÿµÿ‘ÿ|ÿyÿÿÿ¯ÿÐÿóÿ $./þÿØÿ«ÿ~ÿYÿ:ÿ#ÿÿÿ-ÿ=ÿLÿWÿ^ÿaÿdÿiÿyÿÿµÿáÿCh„••†mL%þÿÖÿ²ÿ—ÿ„ÿÿÿ¬ÿÎÿóÿ8KRI5ôÿÆÿžÿxÿ\ÿJÿBÿFÿRÿZÿ_ÿgÿjÿoÿxÿ‰ÿ¤ÿ¿ÿâÿ<_v‰‰{cDùÿÒÿ³ÿžÿÿ“ÿ¢ÿ¾ÿáÿ 0NchdS5ãÿ¸ÿÿoÿ]ÿUÿ]ÿlÿ}ÿŠÿ”ÿ™ÿ—ÿÿŽÿ’ÿ§ÿÇÿíÿEfƒŒy]8àÿ³ÿ…ÿeÿPÿNÿ_ÿ€ÿ±ÿìÿ)[›£™W%ïÿÁÿÿ|ÿmÿhÿpÿwÿ„ÿŒÿÿœÿ ÿ«ÿ¾ÿÕÿúÿ&QsŽš˜‡mGãÿ»ÿÿeÿLÿAÿCÿYÿyÿ©ÿÙÿ 0L]\P;÷ÿÕÿºÿªÿ¢ÿ¢ÿ¬ÿ¸ÿÃÿÊÿÉÿÊÿÆÿÆÿÏÿßÿûÿ"Jnˆ ª¦”yS+ùÿÉÿœÿvÿ^ÿQÿPÿYÿvÿœÿ¿ÿçÿ&& òÿÔÿ´ÿ›ÿÿ‹ÿ—ÿ¤ÿ²ÿ¼ÿÈÿËÿÌÿÏÿÖÿÞÿ÷ÿ;a…¢²¾¶£‹e< áÿµÿŠÿlÿ]ÿZÿcÿ|ÿÿÁÿâÿÿÿÿÿåÿÈÿ§ÿ†ÿwÿtÿyÿ…ÿ—ÿªÿ½ÿÊÿÒÿÚÿäÿóÿDj¬¿ÈðŽmEòÿÌÿ©ÿŽÿÿ}ÿ„ÿ™ÿ³ÿÒÿñÿ   òÿÑÿ²ÿŒÿtÿdÿeÿlÿyÿ‡ÿ•ÿŸÿ©ÿ±ÿ¸ÿÆÿÜÿÿÿ,Y‹·ÜõùòÛ¸b,õÿÅÿÿ}ÿpÿlÿxÿÿ¬ÿÕÿúÿ,3.ûÿ×ÿ²ÿÿuÿdÿaÿkÿyÿˆÿ’ÿ›ÿ¡ÿ§ÿ¯ÿÁÿØÿøÿ!R€ªÈÚâÛϵ”qHöÿÔÿºÿ¨ÿ£ÿªÿ·ÿÊÿÞÿóÿ íÿÍÿªÿ‰ÿnÿ_ÿYÿ^ÿlÿÿŽÿÿ§ÿ³ÿ¼ÿÅÿÓÿêÿ'Ov™¯½À»¯•wS+àÿ½ÿ¦ÿŸÿ¢ÿµÿÊÿíÿ &4=6 Úÿ®ÿ€ÿ`ÿIÿ<ÿ5ÿ?ÿLÿ^ÿiÿzÿ‰ÿ–ÿ«ÿÆÿæÿ 1Vy”¢§¥ž‘€gDãÿÅÿµÿ´ÿ´ÿ½ÿÑÿéÿ÷ÿóÿÜÿ½ÿžÿ„ÿtÿkÿhÿjÿlÿoÿpÿqÿpÿuÿxÿ†ÿ—ÿµÿáÿ.Ro~ˆ†u^F*÷ÿàÿÐÿÄÿÅÿÏÿÙÿêÿþÿíÿÌÿ­ÿÿvÿdÿ]ÿaÿfÿlÿjÿfÿeÿbÿfÿmÿ‚ÿ™ÿ¾ÿèÿ6Thwun]J2ðÿÛÿÏÿÌÿÌÿÍÿÛÿîÿ$ûÿßÿÀÿ¡ÿ‰ÿwÿlÿjÿpÿvÿxÿxÿvÿtÿuÿpÿxÿ†ÿœÿ»ÿáÿ 5CJKF8%éÿÐÿ¿ÿ­ÿ§ÿ©ÿ¸ÿÉÿçÿ 7FH?*ïÿÉÿ§ÿ‹ÿ{ÿtÿsÿ{ÿ‚ÿ‰ÿŽÿÿÿ•ÿšÿ¦ÿ¶ÿÓÿðÿ';GKD9%îÿÍÿ²ÿ–ÿ‚ÿzÿ{ÿ„ÿ™ÿ´ÿÒÿñÿ*>F:&åÿÁÿÿˆÿ~ÿ|ÿƒÿÿ–ÿ—ÿŸÿÿ›ÿžÿ¦ÿ¸ÿÔÿðÿ +CQUQH6' ëÿËÿ°ÿ’ÿ~ÿrÿoÿuÿ‚ÿ™ÿ²ÿÐÿíÿñÿÖÿ»ÿªÿ ÿšÿ›ÿ¡ÿ¥ÿ¢ÿ›ÿ’ÿ‰ÿ„ÿ‰ÿ”ÿ­ÿÐÿóÿ8Q_]XJ2ýÿÚÿ¹ÿ—ÿ}ÿlÿ_ÿaÿkÿ‚ÿœÿ¸ÿÖÿòÿÿÿäÿÅÿ£ÿŒÿ|ÿwÿÿŠÿ‘ÿ›ÿ¤ÿ«ÿ±ÿ¹ÿÉÿ×ÿëÿ .PgswlZ?"äÿÈÿ­ÿ•ÿ}ÿmÿgÿiÿtÿ…ÿ“ÿ©ÿÂÿÖÿëÿúÿúÿéÿÚÿÅÿ³ÿ¦ÿ©ÿ±ÿ´ÿ»ÿ·ÿ¬ÿ¦ÿœÿ•ÿ‘ÿœÿ«ÿËÿôÿ!Ks ©§˜~]/Úÿ«ÿŒÿwÿjÿgÿqÿ†ÿŸÿ¸ÿÓÿêÿûÿúÿéÿÙÿÉÿÂÿÁÿÆÿÖÿæÿòÿ÷ÿðÿèÿàÿÛÿßÿèÿûÿ4Uv‡’—’‰xfN0óÿÖÿ½ÿ®ÿ§ÿ¥ÿ¬ÿ¹ÿÈÿÙÿéÿøÿõÿàÿÈÿ¯ÿ¢ÿœÿ£ÿ»ÿÕÿòÿ 4Ps‹¥µ¸³¨z^?$ ïÿÙÿÊÿÂÿÀÿÅÿÐÿÞÿðÿ  öÿÜÿ¼ÿ¦ÿÿ¦ÿ¶ÿÊÿãÿôÿ$.@Yx™²ÉÙÛÖgD&îÿÝÿÖÿÓÿÓÿÛÿæÿñÿêÿÒÿ¾ÿ´ÿ±ÿ¸ÿÏÿáÿüÿ/9CN]pЍÆàðóíçØÈ­”|`G,$)//, ñÿÒÿ¹ÿ¥ÿ ÿªÿ½ÿ×ÿíÿ "4Hi˜Äé èË®pP6$+9>FE:+ðÿÏÿ²ÿ›ÿ˜ÿ ÿ³ÿÎÿãÿøÿ ,=\ƒ©ÈßëíéäÔ¿©“{fQ>/&&,4=GHLMC/îÿÉÿªÿŽÿ‡ÿ‰ÿ•ÿ¥ÿ¸ÿËÿÞÿèÿ÷ÿ$?d±Óé÷ú÷çж”pQ2 úÿ#5FSWQ@, çÿÂÿ¨ÿ–ÿ“ÿšÿ¥ÿ°ÿ¹ÿÁÿÂÿÂÿÇÿÍÿÞÿõÿ4Y~ŸºÆÏÔÐŵ „`G,ýÿøÿúÿ *,&úÿÝÿ¿ÿ¡ÿŠÿ~ÿ„ÿ™ÿ§ÿ½ÿÍÿÖÿÜÿãÿåÿéÿ÷ÿ ";[u†’–”“‹sgT@0!+031(æÿÂÿ˜ÿ}ÿfÿeÿnÿ~ÿ–ÿ§ÿºÿÈÿÔÿÙÿÝÿèÿøÿ (Gf…• ¤ –€o[B+ ýÿþÿ  +5@@:)êÿÄÿžÿÿiÿaÿfÿmÿ|ÿˆÿ—ÿ¨ÿ±ÿ»ÿÆÿÕÿçÿ7QeuˆŽ‡ziR:" ýÿïÿìÿïÿøÿ*10+üÿÛÿ¹ÿ•ÿ}ÿqÿpÿvÿ„ÿŒÿ‘ÿ•ÿ™ÿ¢ÿ§ÿ³ÿÈÿâÿ&BYjqwvnbTG6#õÿñÿñÿöÿ-468-óÿÍÿ¨ÿ„ÿlÿcÿfÿmÿ~ÿ‘ÿ¤ÿ­ÿ²ÿ·ÿ¾ÿÌÿáÿúÿ3J[dfcXND3'ôÿéÿàÿÛÿâÿìÿúÿ$9HOMA* èÿÁÿ¡ÿÿƒÿÿÿƒÿÿÿ’ÿÿ¥ÿµÿÆÿáÿ"Bas~|o]E*üÿäÿÓÿÈÿ¿ÿÃÿÊÿÙÿëÿ%250 èÿÊÿ°ÿ ÿ™ÿšÿ¡ÿªÿ·ÿ½ÿÂÿÈÿÍÿÔÿÙÿèÿúÿ0DX`dda[K=)÷ÿâÿÌÿ¹ÿ®ÿ¬ÿ²ÿ¿ÿÒÿçÿýÿ ùÿÛÿ¸ÿ›ÿÿnÿiÿnÿ|ÿŠÿšÿ¤ÿ¬ÿµÿ¼ÿÀÿÉÿÚÿðÿ *CT^a_[TD8&ûÿàÿÉÿ°ÿžÿ—ÿ“ÿ ÿ®ÿ¾ÿÏÿßÿèÿêÿãÿÓÿ»ÿ–ÿuÿ^ÿHÿ?ÿBÿMÿ`ÿqÿ‚ÿ’ÿ ÿ°ÿÃÿÔÿíÿýÿ+<ELJA2%øÿíÿÚÿÅÿ¶ÿ¦ÿÿœÿ§ÿ¶ÿÍÿÜÿëÿõÿøÿóÿäÿÅÿžÿwÿSÿ;ÿ(ÿ"ÿ#ÿ,ÿ9ÿIÿYÿiÿ|ÿÿ§ÿÂÿáÿ$;R_ikg^R>"íÿÖÿ¼ÿ§ÿÿ’ÿÿ“ÿ›ÿ©ÿµÿÅÿ×ÿáÿçÿãÿÒÿ¼ÿ£ÿ‹ÿpÿ\ÿNÿGÿJÿKÿNÿQÿ]ÿiÿyÿÿ¬ÿÊÿèÿ ,AS[\VNC9,óÿßÿÐÿÈÿÃÿÈÿÎÿÓÿÙÿßÿàÿßÿÛÿÊÿ²ÿšÿ|ÿkÿRÿMÿPÿ[ÿiÿzÿŠÿšÿ¡ÿ®ÿ»ÿÈÿÛÿðÿ 1@KRTNG>7)#úÿèÿÜÿÖÿÕÿÚÿéÿñÿûÿøÿéÿÖÿ¼ÿ¢ÿ‡ÿtÿfÿWÿSÿSÿXÿaÿnÿ~ÿŒÿ¥ÿ»ÿÝÿýÿ9Tkx}€~nbR<!øÿæÿÙÿÓÿÒÿØÿàÿïÿöÿ øÿäÿÍÿ±ÿ•ÿzÿiÿ`ÿ_ÿdÿpÿ~ÿÿœÿ¬ÿ´ÿÀÿÐÿäÿ1Lbuƒ‹ˆ„wfR?$øÿäÿÒÿÎÿÏÿÎÿ×ÿÞÿçÿðÿôÿðÿæÿÔÿ»ÿ¢ÿŒÿwÿjÿ]ÿ_ÿgÿoÿ}ÿ†ÿ‘ÿ ÿ°ÿÁÿ×ÿóÿ(;O`efgie_[TH8( þÿøÿõÿøÿúÿøÿúÿôÿçÿßÿÃÿ«ÿ‰ÿhÿOÿ?ÿ0ÿ)ÿ(ÿ1ÿ?ÿUÿlÿ…ÿŸÿºÿÙÿøÿ-ET_mttk\I7 ûÿìÿÝÿÖÿÙÿäÿêÿüÿ&%þÿßÿ¿ÿšÿwÿYÿ?ÿ+ÿÿÿ!ÿ-ÿ:ÿOÿbÿ~ÿ™ÿµÿÓÿñÿ/G]muy|wo`PA,øÿãÿÐÿÉÿÉÿÒÿÚÿæÿóÿüÿûÿõÿèÿÓÿ´ÿ™ÿ}ÿ]ÿGÿ3ÿ%ÿ'ÿ)ÿ1ÿ>ÿQÿkÿ‚ÿÿ·ÿÛÿúÿ0HYdikjd\RH8& ÿÿüÿóÿîÿóÿüÿ÷ÿéÿÖÿ¿ÿ©ÿÿuÿaÿMÿ=ÿ1ÿ)ÿ(ÿ)ÿ4ÿHÿ\ÿuÿ”ÿ²ÿÏÿðÿ)B[rˆ‰Œ†zfT@/" ÿÿþÿñÿéÿÝÿËÿ²ÿ™ÿ…ÿpÿZÿJÿBÿEÿLÿWÿfÿvÿˆÿŸÿ´ÿÆÿÝÿõÿ 7N`luzzul`QE:2039@DLOK;1þÿåÿËÿ´ÿÿ†ÿqÿbÿUÿNÿKÿPÿ^ÿjÿƒÿ¡ÿ¼ÿÛÿûÿ0BZhxƒŽ„t]G7'"&,9DHLMD7"øÿáÿÎÿ¾ÿ®ÿ¡ÿ•ÿŠÿÿxÿtÿyÿƒÿŽÿ¢ÿ¶ÿËÿÚÿêÿûÿ)<O]lv{{tlcTQONLNPQLC=.òÿÜÿÈÿ¸ÿªÿœÿ“ÿ’ÿ–ÿšÿŸÿ¨ÿ±ÿ¾ÿÌÿÝÿêÿúÿ #(.6>DFGCB@:444>DPZ[_^UG4þÿæÿÍÿ³ÿ ÿÿÿvÿwÿ}ÿ‡ÿ˜ÿ¯ÿÇÿàÿõÿ *098797;;>;;4*  )3852* üÿçÿÚÿÑÿÅÿ¹ÿ¨ÿšÿÿ†ÿÿƒÿÿ¦ÿºÿÒÿêÿ"/:EKPY[TH>3#  úÿéÿÑÿÁÿµÿ§ÿžÿ”ÿÿˆÿ‰ÿˆÿŒÿ™ÿ¦ÿ¸ÿÐÿðÿ.<CLSZahig_N8'%$" ÷ÿÝÿÎÿ¾ÿ¯ÿ£ÿ”ÿ„ÿzÿxÿuÿwÿ}ÿ†ÿ”ÿ¨ÿºÿÒÿëÿ$3<DHHKFE=5'  #,,(÷ÿèÿÔÿÂÿ³ÿ©ÿ ÿ“ÿˆÿ{ÿxÿvÿwÿ}ÿŠÿ”ÿ ÿ¬ÿ»ÿËÿÚÿéÿúÿ+:ELK@:, üÿõÿïÿðÿõÿ !üÿèÿÒÿ»ÿ¥ÿ•ÿ†ÿ{ÿsÿoÿiÿlÿrÿ‚ÿ“ÿ©ÿ¿ÿÕÿçÿõÿûÿþÿÿÿþÿ  +152(öÿçÿâÿäÿäÿèÿìÿïÿóÿùÿöÿñÿíÿçÿâÿÜÿÐÿÆÿ¹ÿ­ÿ¢ÿ™ÿ‹ÿƒÿ‚ÿÿ‰ÿ–ÿ§ÿ¾ÿÔÿçÿüÿ%.5:<@<1& øÿôÿðÿðÿ÷ÿüÿÿÿþÿõÿëÿÞÿÏÿ¿ÿ·ÿ±ÿ°ÿ¯ÿ¸ÿ¶ÿ´ÿ³ÿ´ÿ²ÿ¸ÿ¾ÿÇÿÒÿâÿìÿúÿ$*28>@D?9.öÿðÿîÿïÿòÿòÿöÿöÿõÿîÿßÿÎÿÀÿ®ÿ§ÿœÿ™ÿ•ÿ•ÿ–ÿ›ÿ˜ÿ˜ÿ™ÿžÿ­ÿ¾ÿÐÿéÿ,<IZgpokc_N@. ýÿùÿ÷ÿøÿ÷ÿñÿéÿäÿÔÿÉÿºÿ­ÿŸÿ–ÿ”ÿŽÿ‰ÿ‹ÿŽÿ“ÿ™ÿ™ÿœÿŸÿ£ÿªÿ¹ÿÌÿáÿøÿ#8L\imvvngWD4! ÿÿñÿÚÿÂÿ¨ÿ”ÿÿpÿeÿ[ÿVÿUÿZÿaÿkÿwÿˆÿ ÿµÿÎÿçÿÿÿ-AQ`ktxzxtk^PD6+%ôÿäÿÕÿÌÿ½ÿ·ÿ¯ÿ¦ÿ¡ÿ’ÿ‰ÿ~ÿqÿdÿ_ÿ^ÿ_ÿgÿyÿ•ÿ´ÿÛÿýÿ:To‚ŸŸš‘‡|gS?/*"! ðÿÛÿÊÿºÿªÿ¤ÿŸÿ™ÿ˜ÿ˜ÿ•ÿ”ÿ’ÿ“ÿ—ÿ˜ÿ˜ÿ¢ÿ¯ÿÂÿ×ÿîÿ5Pj’Ÿ¦¦ž”„nYH?5,)&"þÿíÿàÿÕÿÌÿÀÿµÿ¦ÿ™ÿ‹ÿÿzÿtÿpÿsÿ}ÿ‹ÿšÿ±ÿÎÿêÿ,IdvŒ–¢§§¡˜Œsj_SKF@;2) ýÿíÿÞÿÔÿÏÿÊÿÈÿÀÿ¹ÿ±ÿ©ÿ¢ÿ™ÿ—ÿ’ÿ”ÿžÿ©ÿ»ÿÌÿßÿöÿ0OqŠœ²ºº¸­¢ƒvpicda[VJ9$þÿðÿéÿÞÿÙÿÍÿÀÿ´ÿ¨ÿžÿ˜ÿ—ÿ”ÿ™ÿ§ÿ¸ÿÉÿÚÿðÿ$5Mh~œ¬¶º¹³¨›„ztjcYRI=2)$""  ûÿçÿÖÿÄÿ°ÿ¤ÿÿ™ÿÿªÿÀÿÙÿóÿ )G^rƒ‘™žŸ¤£ž—”’‘–™™˜“ˆv_D,  öÿèÿÜÿÓÿÌÿÑÿØÿáÿòÿ1KcyŠ—ž™—„}ywz{yxxshXH7-$ ûÿïÿèÿãÿßÿáÿãÿäÿéÿðÿùÿ+9Ng}“£¬¯®¦›’ƒ~}{qole]QH>8304<==90!þÿñÿâÿÔÿÑÿÐÿÔÿÜÿéÿôÿ/Jdœ³½Âﮣ|rkjikia[M@4'"  þÿ÷ÿùÿûÿ)8EYhq‰“•’“‘‹‡ˆ…€zoj_Q?+ þÿ÷ÿïÿêÿçÿíÿøÿ 2FVix…vrjfdc`aaa[RB4'ÿÿùÿýÿ  ýÿïÿáÿÕÿÊÿÆÿÅÿÈÿÓÿåÿûÿ7Sh}…qaP>0'!#  øÿäÿÔÿÎÿÉÿÈÿËÿÐÿÓÿÕÿÜÿàÿâÿäÿäÿæÿåÿçÿçÿëÿôÿøÿûÿ (7ELY\UPC5* þÿøÿìÿÞÿÑÿ½ÿ¬ÿ¤ÿ¥ÿ¥ÿ«ÿ´ÿ½ÿÁÿÅÿÊÿÊÿÃÿ½ÿ¸ÿ¶ÿ´ÿºÿÀÿÇÿÕÿèÿýÿ(<OYfffcUD/ ùÿõÿëÿßÿÙÿÉÿ»ÿ®ÿŸÿ’ÿ‡ÿ„ÿ„ÿ‰ÿÿ–ÿ ÿ¦ÿ¬ÿ±ÿµÿ²ÿ®ÿ®ÿ°ÿ¯ÿ¶ÿ½ÿËÿÜÿìÿ;Wp„ŽˆzgVE2ùÿïÿäÿØÿÊÿ¿ÿµÿ²ÿ®ÿ«ÿªÿªÿ«ÿªÿ¢ÿ›ÿ—ÿ“ÿÿ‰ÿ‡ÿ‹ÿŽÿšÿªÿ¼ÿÓÿëÿ %C_~•¥«®¬ž|jWK>2(ýÿæÿÑÿ½ÿ¬ÿŸÿ›ÿ›ÿ¢ÿ©ÿ±ÿ·ÿ»ÿ»ÿ²ÿ§ÿŸÿ”ÿŠÿ„ÿˆÿÿ’ÿ ÿ«ÿ¿ÿÛÿFi„¡³ÁÆÅ¼©˜‡wjaQ>(úÿâÿÈÿ¯ÿšÿ•ÿŽÿ“ÿ›ÿ¤ÿ´ÿÀÿÆÿÉÿÄÿ¿ÿ¸ÿ®ÿ¤ÿŸÿ™ÿ™ÿÿ§ÿ³ÿÉÿæÿ%E_x ¨©¤ž’‹‚tk^L9"üÿéÿÙÿÉÿ½ÿ»ÿ»ÿÀÿÁÿÀÿÁÿ·ÿ¯ÿ¤ÿÿ“ÿÿŒÿÿ˜ÿ¡ÿ°ÿÂÿØÿïÿ 6J\ju}|~}yutng\L4ìÿØÿÆÿ¿ÿ»ÿ¾ÿÅÿÈÿÎÿÔÿÕÿÐÿËÿÅÿºÿ³ÿ®ÿ£ÿ›ÿ˜ÿ—ÿ ÿ¥ÿ¯ÿÂÿÚÿöÿ0K]kty{yskf`UL<'ÿÿäÿÏÿ¼ÿ¯ÿ¦ÿ§ÿ¨ÿ±ÿºÿ¿ÿ¿ÿÀÿ½ÿºÿ´ÿ«ÿ¤ÿ¢ÿ¡ÿŸÿŸÿ ÿ¥ÿ­ÿºÿÈÿÝÿíÿ+7BJPQQQMNK@5%úÿãÿÍÿ´ÿ§ÿšÿ–ÿ˜ÿ™ÿŸÿ¤ÿ«ÿ¬ÿ©ÿ£ÿšÿ•ÿˆÿ~ÿ|ÿ~ÿ…ÿŒÿšÿ«ÿÀÿÏÿåÿýÿ#38;3+$ïÿÚÿÊÿ¹ÿªÿ£ÿ ÿ¡ÿžÿ ÿœÿœÿ˜ÿ’ÿŒÿ‡ÿ~ÿ{ÿ}ÿyÿ}ÿƒÿ–ÿ¥ÿ´ÿÌÿãÿøÿ %1;894.)&%!!ôÿäÿÐÿÂÿ·ÿ±ÿ²ÿ³ÿ·ÿ½ÿÂÿÃÿÇÿÄÿ¿ÿ¸ÿ¯ÿ¥ÿ ÿšÿ–ÿ“ÿ“ÿ•ÿ›ÿ¥ÿ³ÿÄÿØÿóÿ'6DPPPL?70*"úÿîÿÜÿÎÿÄÿ¼ÿºÿºÿÀÿÑÿâÿïÿýÿôÿáÿËÿ·ÿ£ÿ•ÿˆÿŒÿ’ÿ›ÿ®ÿ¿ÿÏÿîÿ #8N]hkdWI:/!óÿåÿÔÿÅÿ¸ÿ¯ÿ«ÿ­ÿ²ÿºÿÈÿÖÿâÿñÿûÿöÿñÿåÿßÿÙÿÕÿÕÿÖÿáÿðÿ%4EUaije^WPG</"üÿãÿËÿ²ÿŸÿ“ÿ‘ÿ“ÿŸÿ´ÿÊÿàÿôÿ úÿðÿêÿçÿáÿáÿçÿóÿ0Ibs‹‘ŒzlYND5)÷ÿäÿÎÿ¹ÿ®ÿ¡ÿ™ÿ¡ÿ©ÿ¸ÿËÿáÿïÿ  ÿÿöÿöÿõÿùÿÿÿ #4MbzŸ¤¤’‚qeYOB/ãÿÃÿ§ÿ‘ÿ‚ÿÿÿ…ÿ•ÿ«ÿ½ÿÒÿçÿ÷ÿ   (2@LVkz…ŠŠ‡{sobQ?&èÿÇÿ¬ÿ”ÿƒÿÿ{ÿ~ÿ…ÿ‘ÿ™ÿ¬ÿ¼ÿÌÿÙÿáÿâÿåÿíÿûÿ&2<JV^fmqsslmkifca\SE0ùÿÓÿ°ÿ”ÿÿoÿgÿiÿrÿ}ÿŒÿšÿ¨ÿµÿ¼ÿÀÿÀÿºÿ»ÿ¼ÿ¼ÿÅÿÓÿáÿñÿ,EVes€†‡ƒvgZPJB8+çÿÊÿ©ÿ‹ÿpÿ^ÿTÿOÿQÿXÿ`ÿjÿxÿÿ‡ÿ‰ÿŠÿ‰ÿ‚ÿ‚ÿ†ÿŒÿ™ÿªÿÀÿÚÿñÿ $:M^lz}}tiZK@80($ýÿåÿÈÿ¨ÿŽÿvÿdÿVÿLÿHÿLÿQÿWÿaÿgÿpÿmÿlÿkÿjÿhÿkÿnÿzÿ‹ÿÿ³ÿÍÿèÿ1GXdouvph_PE:*âÿÃÿ§ÿŽÿsÿbÿVÿSÿRÿZÿeÿqÿwÿ€ÿ‚ÿ€ÿÿ{ÿrÿgÿ^ÿ]ÿ_ÿgÿvÿÿ¦ÿ½ÿÙÿôÿ,G\r€‡ˆ‡ƒ}wmfXB'òÿ×ÿ¸ÿ ÿŒÿÿ{ÿuÿvÿÿ„ÿˆÿÿ‘ÿ’ÿ“ÿ—ÿ’ÿŒÿŠÿ‹ÿŽÿ—ÿ¥ÿ³ÿÃÿÖÿìÿúÿ+:GVcitxyƒ{p]F) îÿÔÿÁÿ³ÿ«ÿ¨ÿªÿ³ÿºÿÁÿÆÿÇÿÅÿ¿ÿµÿ§ÿ™ÿÿˆÿŠÿÿÿ«ÿÀÿ×ÿïÿ !1?Q]jsy„€„}rhV>$æÿÏÿ»ÿ¯ÿ¨ÿ­ÿ¹ÿÆÿÚÿêÿûÿýÿðÿåÿÕÿÆÿ¶ÿ´ÿ¹ÿÊÿÕÿåÿõÿ$:IYdkotuy{‚‡…}weH.óÿÙÿÇÿ½ÿ¶ÿºÿÁÿÏÿÜÿïÿýÿ þÿ÷ÿîÿçÿâÿâÿæÿñÿûÿ 3BUgt}‡…‚|uulcYND6" üÿéÿÚÿÒÿËÿÌÿÎÿÏÿÖÿâÿëÿðÿ÷ÿüÿÿÿüÿûÿöÿøÿûÿ '1=IT\fmrrxz{}zupdU;ýÿàÿËÿ¼ÿ¯ÿ©ÿ©ÿ¯ÿºÿÄÿÑÿÛÿäÿìÿíÿêÿæÿåÿèÿåÿìÿõÿÿÿ*7DPW^hmmvqtroi^WK9& øÿßÿÏÿÇÿÀÿÅÿÈÿÎÿÒÿÛÿâÿçÿêÿêÿãÿÙÿÔÿÎÿÄÿÄÿÃÿÊÿÒÿäÿôÿ #<M[dmled`\\_]YYSK9"çÿËÿ¬ÿ˜ÿ‰ÿ~ÿ…ÿÿœÿ¯ÿÇÿÛÿìÿþÿøÿòÿëÿäÿàÿáÿëÿöÿ (4@HMORSPLMIKFA6&ðÿÓÿ¹ÿžÿÿ‚ÿÿ€ÿ†ÿÿšÿ¨ÿ¶ÿÃÿËÿÔÿÝÿßÿàÿÞÿàÿåÿéÿóÿ#4FR]gigb`VNE=6.$üÿåÿÑÿ¹ÿ¥ÿ•ÿˆÿÿ‚ÿ†ÿ‘ÿ—ÿ¦ÿ°ÿ¹ÿÅÿÎÿÔÿÖÿÓÿÑÿÒÿÚÿåÿñÿ&7G[djtux~xvmbWE/õÿÙÿ»ÿ ÿ‹ÿzÿpÿnÿpÿwÿ~ÿ†ÿ‘ÿžÿ©ÿ±ÿ¸ÿ¿ÿÆÿÊÿÎÿÓÿÙÿåÿøÿ *9K]hpz‚zyzsof[O>% çÿÌÿ²ÿœÿ‰ÿ}ÿyÿuÿsÿvÿxÿ…ÿŽÿ•ÿœÿ¢ÿ©ÿ®ÿ±ÿµÿ¿ÿÉÿÖÿìÿ-AO\gjpslkkjiffb[SC.ôÿÕÿ¶ÿ›ÿŠÿ|ÿuÿrÿsÿyÿ€ÿ†ÿ‘ÿ˜ÿŸÿ¢ÿ¢ÿ¡ÿžÿŸÿ§ÿ°ÿ¾ÿÎÿãÿýÿ.BZhw~‚ƒ~tmcXPG@3"çÿÏÿºÿ§ÿ•ÿŠÿ‚ÿ‚ÿ„ÿÿ~ÿ‚ÿ…ÿ†ÿ‹ÿÿÿÿÿ‘ÿšÿ¦ÿ½ÿ×ÿìÿ-@LZcglszz{vohXC(ïÿÑÿºÿ¤ÿ”ÿŒÿ†ÿ‡ÿŽÿ”ÿ ÿ¦ÿ®ÿ±ÿµÿ°ÿ¬ÿŸÿ™ÿ”ÿ‘ÿ–ÿÿ¬ÿÄÿÚÿóÿ %:L`oyƒ‚~||rj\L=%çÿÎÿ¹ÿ¦ÿšÿ“ÿŽÿŒÿÿ—ÿ›ÿ§ÿ±ÿ¶ÿ»ÿ¹ÿºÿ¶ÿ°ÿªÿ¨ÿ­ÿ¸ÿÄÿÒÿæÿýÿ#6BQ[bgilstyxtm[G0÷ÿÜÿÈÿ´ÿ¨ÿ£ÿœÿœÿžÿ›ÿ—ÿÿœÿžÿžÿ¢ÿ¡ÿ ÿ ÿ¥ÿ°ÿ¾ÿÊÿÙÿêÿüÿ&:KZdnpollhgddbUG3ýÿêÿÕÿÁÿ·ÿ°ÿ°ÿ²ÿ´ÿ¸ÿ¾ÿÄÿÄÿÃÿÀÿºÿµÿªÿ©ÿ¦ÿ ÿ¦ÿ®ÿ¼ÿÊÿÙÿðÿ !5HXckqy}~|x{tm^H) ñÿÜÿÈÿ´ÿ®ÿ©ÿ§ÿ£ÿ«ÿ²ÿ·ÿºÿ»ÿ¼ÿ¼ÿ¿ÿÁÿÇÿËÿÕÿÞÿæÿñÿýÿ(4BHNR\_gr{‚†‰‡€uaI.÷ÿêÿÞÿ×ÿÑÿÏÿÑÿÕÿ×ÿÕÿÕÿÓÿËÿÊÿÃÿÀÿÁÿÉÿÔÿåÿöÿ $:PantxuokgdbbdiomaTG8&ýÿúÿ÷ÿòÿíÿêÿëÿæÿåÿßÿÜÿßÿÛÿÞÿâÿàÿèÿïÿúÿ&:IZejqwuurlpmolf[R>)òÿêÿåÿåÿæÿïÿóÿùÿþÿûÿöÿíÿäÿÞÿ×ÿÌÿÌÿÌÿÐÿÕÿÝÿìÿþÿ#<R_nuvwrmd[PONEB=-ñÿâÿÕÿÎÿÎÿÎÿÓÿÙÿàÿäÿëÿïÿëÿêÿàÿÛÿ×ÿÕÿÒÿÔÿ×ÿØÿÞÿëÿùÿ ):IX\\\XUOICBB@90&úÿæÿ×ÿÇÿ¸ÿ­ÿ«ÿ§ÿ§ÿ¯ÿ·ÿÀÿÈÿÏÿÕÿÙÿÕÿÏÿÊÿÈÿÇÿÆÿÑÿÝÿæÿõÿ#/4<DHHB><4.# õÿâÿÖÿÆÿ¸ÿ³ÿ³ÿ®ÿ¯ÿµÿ¼ÿ¾ÿ½ÿ¿ÿ¾ÿ¹ÿ¸ÿ·ÿ¯ÿ¬ÿ®ÿ®ÿ³ÿ¸ÿÀÿÏÿßÿíÿ)8BBB8-$üÿöÿêÿØÿÁÿ¬ÿ˜ÿ‡ÿ{ÿrÿtÿ|ÿ…ÿ‰ÿ•ÿ›ÿ¦ÿ­ÿ®ÿ¶ÿ¸ÿ½ÿ»ÿºÿ¹ÿ¼ÿ¿ÿÃÿÉÿËÿÒÿÜÿìÿùÿ!&#"úÿòÿæÿÎÿ¸ÿ¡ÿˆÿtÿdÿYÿQÿJÿNÿOÿWÿbÿlÿuÿ~ÿ}ÿ„ÿ…ÿ‚ÿ†ÿŒÿ“ÿÿ¬ÿ·ÿÅÿ×ÿãÿðÿÿÿùÿñÿëÿéÿÝÿØÿÐÿ¼ÿ¢ÿˆÿpÿZÿIÿ=ÿ9ÿ:ÿBÿKÿPÿ[ÿ_ÿ`ÿcÿ_ÿZÿTÿVÿXÿ_ÿlÿzÿÿ©ÿÁÿÙÿóÿ #-00/&üÿòÿïÿåÿßÿÔÿÊÿ³ÿ™ÿ‚ÿpÿZÿMÿDÿ=ÿ=ÿ?ÿEÿMÿVÿ[ÿ^ÿbÿaÿZÿWÿXÿYÿYÿ`ÿiÿyÿ‰ÿšÿ±ÿËÿãÿþÿ$221-*#÷ÿðÿãÿÖÿÁÿ¬ÿšÿ„ÿoÿaÿWÿLÿFÿGÿFÿDÿBÿAÿ@ÿDÿ?ÿ>ÿ@ÿAÿFÿSÿ`ÿoÿ}ÿŠÿšÿ¨ÿ·ÿÂÿÏÿÞÿîÿûÿ  ýÿóÿâÿÎÿ·ÿ ÿˆÿuÿiÿ]ÿ^ÿYÿaÿbÿ^ÿ`ÿ_ÿ]ÿXÿSÿRÿOÿRÿTÿ[ÿaÿlÿ~ÿŽÿÿ°ÿÁÿÔÿêÿ÷ÿ ÿÿ÷ÿïÿéÿÔÿÁÿ°ÿ›ÿ‹ÿ~ÿyÿuÿmÿrÿrÿuÿsÿqÿlÿeÿaÿ^ÿ^ÿbÿiÿqÿ{ÿ‰ÿ˜ÿ¥ÿµÿÇÿÛÿèÿöÿ  þÿöÿèÿ×ÿÅÿ¶ÿ¥ÿ—ÿ‹ÿ‡ÿ…ÿ‡ÿŒÿ’ÿ–ÿ˜ÿ–ÿŒÿ†ÿ€ÿtÿkÿjÿhÿiÿrÿÿ’ÿ¥ÿ»ÿÔÿéÿ$3<><:4( ýÿïÿÜÿÊÿ¶ÿ¥ÿ–ÿŒÿ„ÿ|ÿ~ÿ„ÿ‹ÿ’ÿÿªÿ­ÿ­ÿ©ÿªÿ¥ÿÿ–ÿÿÿÿ”ÿ¡ÿ¬ÿºÿÑÿèÿøÿ #04:8/.$  üÿìÿÚÿÍÿ¹ÿ¨ÿœÿŽÿÿzÿuÿqÿwÿxÿvÿxÿwÿ|ÿÿ‚ÿ‚ÿ‰ÿÿ—ÿ¡ÿ®ÿ¿ÿÈÿÔÿàÿðÿýÿ  '-21,&"þÿõÿæÿ×ÿÈÿ½ÿ³ÿ¬ÿ¦ÿ¥ÿ¤ÿ¦ÿ¨ÿ¤ÿ¢ÿ£ÿ™ÿŽÿ‡ÿzÿpÿiÿeÿeÿlÿzÿŒÿŸÿ®ÿ¿ÿÑÿáÿîÿ (-.--*#  ýÿêÿØÿÆÿ³ÿ¢ÿ—ÿ”ÿÿÿÿ‘ÿšÿ¢ÿ©ÿ­ÿ¨ÿ¡ÿ›ÿ“ÿŽÿ‡ÿˆÿ†ÿ‹ÿÿ›ÿ¥ÿ¯ÿºÿÅÿÓÿÚÿäÿìÿ÷ÿøÿéÿÕÿÃÿ¶ÿ¨ÿ ÿšÿ“ÿ”ÿžÿ¨ÿ±ÿµÿ¹ÿ·ÿ´ÿ®ÿ£ÿ—ÿÿŽÿÿ“ÿ—ÿ£ÿ²ÿÀÿÊÿ×ÿåÿïÿöÿÿÿ  ýÿïÿßÿÒÿÂÿ´ÿ­ÿ¦ÿ¢ÿ¡ÿ¨ÿ²ÿ¹ÿÃÿÈÿÊÿËÿËÿÊÿÇÿÄÿÂÿÁÿ¿ÿÊÿÙÿÝÿêÿöÿÿÿ þÿ÷ÿïÿæÿØÿÊÿÀÿ½ÿ¸ÿ´ÿ·ÿ½ÿÄÿÍÿÖÿÜÿÚÿØÿÓÿÎÿÌÿÂÿÀÿÄÿÈÿÍÿÛÿèÿõÿ"-6AJRUVWPE7,!ôÿãÿÖÿÈÿ½ÿ¸ÿ³ÿ³ÿ¶ÿ¿ÿÅÿËÿ×ÿÞÿäÿêÿéÿàÿÜÿÕÿÊÿÄÿÄÿÈÿÕÿàÿïÿÿÿ'08=CHJKIHGHGDC@;0"úÿèÿÐÿ¾ÿ²ÿ­ÿ§ÿ¬ÿ´ÿ¿ÿÉÿ×ÿáÿçÿêÿêÿãÿåÿçÿâÿæÿïÿûÿ $/=ELT\abhjc^XNHC>3%ÿÿñÿäÿÝÿÙÿÔÿÒÿÕÿÖÿ×ÿÚÿÚÿÞÿÝÿÛÿØÿ×ÿÙÿÞÿåÿëÿöÿ!09HQV\bghedd^XQJF>7,!÷ÿéÿÜÿ×ÿØÿØÿÜÿäÿèÿîÿóÿðÿïÿëÿäÿÜÿÚÿÛÿÜÿêÿõÿ%4?MV[dnv€{uoeZOA4' øÿïÿèÿæÿäÿäÿçÿëÿðÿôÿõÿúÿýÿþÿøÿîÿêÿáÿãÿìÿöÿ%0>ENXdmrx~|uoj^VMC0ôÿéÿäÿäÿäÿâÿãÿäÿæÿéÿïÿðÿôÿòÿñÿòÿðÿôÿüÿ"->GRWX]`fmqvtvyuleXP=1(  õÿêÿáÿßÿÜÿÝÿäÿñÿ':JU\hsyy~{uqnd\YRID=4& ýÿûÿþÿ  úÿðÿëÿìÿðÿøÿ#&,6:BNWcmy‚‚}umaS?, ôÿðÿðÿðÿðÿöÿþÿ  øÿôÿõÿþÿ!).147@JTbmpwzushXL=* ûÿõÿóÿóÿõÿýÿ þÿ !+9CGBDACBBCJLOORVWQRG8& ýÿöÿñÿïÿñÿôÿúÿüÿöÿòÿìÿêÿðÿõÿ &036?FLOTZ\_[QJF?70& þÿ÷ÿîÿêÿæÿëÿîÿôÿýÿ üÿõÿîÿìÿêÿóÿÿÿ -59;<659<@FHGDF@93-)# ÿÿøÿñÿîÿéÿåÿèÿëÿîÿòÿõÿùÿöÿóÿñÿñÿëÿëÿïÿ÷ÿ #(%'++35<CEBA=8."ûÿñÿãÿÞÿÝÿÝÿßÿßÿàÿÞÿàÿåÿæÿàÿÞÿàÿÙÿÓÿÍÿÌÿÌÿÔÿÚÿèÿôÿ  þÿïÿàÿÖÿÍÿÅÿ½ÿ¼ÿ¼ÿ½ÿÄÿÉÿËÿÏÿÐÿÏÿÎÿÊÿÃÿ¾ÿºÿ¶ÿµÿ·ÿÀÿËÿÜÿêÿöÿ   öÿëÿÚÿÈÿ¶ÿ£ÿ’ÿ‰ÿÿ|ÿ}ÿ…ÿŽÿšÿ¨ÿ·ÿÄÿËÿÎÿÌÿÂÿºÿ³ÿ¬ÿ©ÿ¯ÿ¸ÿÅÿÔÿáÿíÿôÿýÿüÿýÿþÿüÿùÿýÿ ùÿêÿ×ÿÄÿ±ÿ¡ÿ‘ÿ‡ÿÿzÿvÿtÿwÿzÿÿŠÿ’ÿ˜ÿ›ÿœÿŸÿÿžÿžÿ ÿ¢ÿ°ÿÄÿÓÿäÿôÿýÿ  !$&&$ ñÿÞÿÍÿ½ÿ¬ÿŸÿ”ÿŒÿ‰ÿŠÿ‰ÿŒÿ”ÿšÿ¢ÿ£ÿ¡ÿ¥ÿŸÿœÿ™ÿšÿ“ÿ™ÿ¦ÿ³ÿÆÿÚÿîÿüÿ"(/6:BEIDA6) ýÿëÿØÿËÿÀÿ³ÿ®ÿªÿ¡ÿœÿšÿšÿšÿ™ÿ“ÿ”ÿ–ÿ”ÿ—ÿ™ÿžÿ¦ÿ²ÿ¾ÿÎÿàÿìÿöÿûÿýÿýÿ &7BOXXZTLB7%ÿÿïÿâÿÙÿÓÿÊÿÇÿÃÿÅÿÄÿÇÿÆÿÂÿºÿ²ÿ¯ÿ£ÿŸÿ•ÿ”ÿ›ÿ§ÿ¶ÿÈÿÚÿêÿöÿûÿúÿúÿùÿøÿüÿ +8FXaf`TA+ûÿéÿ×ÿÈÿÂÿÃÿ¿ÿÁÿÊÿÍÿÑÿÔÿÓÿÍÿÈÿ¿ÿ·ÿ®ÿ¢ÿ¤ÿ¥ÿ®ÿ»ÿËÿÜÿìÿúÿúÿþÿüÿøÿôÿôÿõÿ÷ÿùÿ %1563,øÿëÿßÿÕÿÐÿËÿÈÿÇÿÉÿÎÿÎÿÈÿÅÿ½ÿµÿ­ÿ¡ÿ™ÿšÿžÿ§ÿ²ÿ¿ÿÌÿØÿàÿçÿëÿìÿïÿòÿ÷ÿüÿýÿ  üÿëÿÜÿÐÿÄÿ¼ÿ¹ÿ²ÿ³ÿ¶ÿ¿ÿÄÿÆÿÈÿÅÿÄÿÁÿ¼ÿ²ÿ©ÿ¤ÿ ÿŸÿ£ÿ­ÿ¶ÿ½ÿÄÿÇÿÆÿÇÿÊÿÌÿÒÿÙÿãÿíÿõÿùÿþÿýÿõÿîÿáÿÔÿÇÿ¿ÿµÿ®ÿ§ÿ¤ÿ£ÿ¤ÿ¦ÿ§ÿªÿ«ÿ¨ÿ¢ÿ¤ÿ ÿ”ÿ”ÿÿÿ‘ÿ•ÿÿªÿ´ÿ¿ÿÂÿ½ÿ¼ÿ¸ÿµÿ¶ÿ¼ÿÇÿÑÿÝÿçÿíÿ÷ÿûÿýÿúÿõÿíÿàÿÏÿÃÿ´ÿ«ÿ§ÿ¤ÿ¡ÿ¡ÿ£ÿÿÿŸÿžÿ˜ÿ–ÿ’ÿŠÿÿ{ÿwÿvÿ}ÿ…ÿ”ÿ¦ÿ¶ÿ¾ÿÄÿ¿ÿ·ÿ©ÿŸÿ—ÿ’ÿŽÿ—ÿ¡ÿ±ÿÄÿÓÿÞÿêÿóÿõÿóÿëÿßÿÏÿÄÿ·ÿ¬ÿŸÿžÿšÿ™ÿšÿŸÿ¤ÿ£ÿ ÿŸÿ™ÿ’ÿˆÿÿvÿnÿkÿqÿÿÿŸÿ®ÿ·ÿ¾ÿÁÿ¿ÿ¶ÿ­ÿ¨ÿ¡ÿ¡ÿ¡ÿ§ÿ®ÿºÿÉÿÔÿãÿêÿíÿìÿåÿÚÿÊÿ¾ÿ°ÿŸÿ•ÿŒÿŒÿ’ÿ–ÿÿ¨ÿ®ÿ°ÿ®ÿ«ÿ¦ÿÿ‘ÿƒÿ}ÿzÿ}ÿ†ÿÿšÿ¥ÿ±ÿ´ÿ³ÿ­ÿ¤ÿžÿ•ÿ”ÿ•ÿ›ÿ¢ÿ©ÿ°ÿµÿ¼ÿÃÿÆÿÆÿÈÿÄÿ¾ÿµÿ©ÿ£ÿ ÿ˜ÿ‹ÿŠÿŠÿŒÿÿ•ÿ–ÿšÿšÿ˜ÿÿŠÿƒÿÿÿ…ÿ‹ÿ—ÿ£ÿ­ÿµÿ¹ÿ²ÿ¬ÿ¥ÿÿ‘ÿŒÿŠÿ‹ÿÿ˜ÿžÿ¨ÿ°ÿ¶ÿ¸ÿ¹ÿºÿ°ÿªÿ§ÿŸÿ—ÿ“ÿ’ÿŽÿÿÿ“ÿ“ÿ›ÿÿœÿ˜ÿ˜ÿŽÿˆÿÿyÿwÿyÿÿŒÿšÿ§ÿ·ÿ¿ÿ¼ÿ¹ÿ³ÿ¥ÿ—ÿÿŒÿ‰ÿ‹ÿÿÿ–ÿ ÿ¡ÿ¡ÿ¡ÿœÿ˜ÿ’ÿ‰ÿÿyÿuÿsÿrÿvÿxÿ|ÿƒÿˆÿƒÿ„ÿ€ÿÿxÿpÿhÿ`ÿ\ÿ]ÿaÿnÿÿÿŸÿ¬ÿ´ÿ¶ÿ´ÿ¬ÿ¢ÿžÿ”ÿÿ‘ÿ‘ÿ“ÿ˜ÿœÿŸÿ£ÿ¥ÿÿ™ÿÿ…ÿzÿoÿfÿ]ÿYÿZÿYÿaÿhÿrÿ}ÿ€ÿ‚ÿ…ÿ~ÿwÿnÿgÿaÿ]ÿ`ÿcÿmÿzÿ‡ÿ“ÿÿ¡ÿ¡ÿ¢ÿœÿ—ÿ“ÿÿÿÿ•ÿ—ÿœÿ¢ÿ¨ÿ¯ÿ«ÿªÿ¥ÿžÿÿ„ÿqÿ`ÿVÿOÿFÿCÿCÿEÿNÿXÿaÿjÿnÿnÿoÿhÿdÿ`ÿ_ÿdÿkÿsÿ€ÿÿ˜ÿšÿ¡ÿ›ÿ“ÿŠÿ„ÿ{ÿvÿuÿ{ÿ€ÿ‡ÿÿšÿ¡ÿ¤ÿ¦ÿ¦ÿ¢ÿšÿ“ÿ‹ÿ‚ÿzÿrÿgÿ^ÿTÿPÿLÿGÿIÿKÿLÿQÿRÿSÿSÿNÿLÿKÿPÿUÿ]ÿdÿqÿ|ÿˆÿÿ’ÿ’ÿ•ÿŽÿ‰ÿ†ÿ‹ÿ‘ÿ’ÿ”ÿ™ÿ—ÿšÿ˜ÿ”ÿÿ…ÿ~ÿuÿmÿlÿeÿeÿdÿaÿcÿbÿaÿ`ÿ]ÿ^ÿ]ÿ\ÿ]ÿZÿWÿWÿ\ÿ^ÿ`ÿiÿtÿ€ÿ…ÿÿ”ÿ“ÿ’ÿŒÿŠÿ†ÿ‡ÿŒÿ“ÿšÿ¤ÿ®ÿ¹ÿ¾ÿÃÿÄÿÀÿ¸ÿ®ÿ¤ÿ™ÿÿƒÿ}ÿuÿrÿrÿrÿnÿmÿnÿlÿiÿhÿgÿfÿdÿaÿdÿeÿjÿtÿƒÿ•ÿÿ§ÿ¬ÿ¬ÿ©ÿ£ÿžÿ—ÿ–ÿ™ÿšÿ¥ÿ¬ÿ·ÿÅÿÑÿ×ÿÚÿßÿàÿÜÿÕÿËÿÃÿ¿ÿ¶ÿ´ÿ«ÿ©ÿªÿªÿ©ÿ£ÿŸÿ¢ÿžÿ™ÿ“ÿŒÿŠÿ…ÿƒÿˆÿÿÿªÿ¿ÿÐÿÜÿáÿãÿáÿÜÿÒÿÈÿÀÿÀÿÅÿÊÿÔÿßÿïÿüÿ  ÿÿùÿòÿëÿèÿæÿçÿäÿåÿåÿåÿÜÿÙÿÕÿÌÿÂÿºÿ¶ÿ±ÿ¯ÿ·ÿÀÿÏÿàÿìÿøÿþÿøÿóÿíÿéÿçÿçÿîÿúÿ &-+,)& !! øÿðÿîÿôÿúÿÿÿ   '/5<CFFA87768;;??DAA?<6651,)*017<BFHE<7)%"',8EQT[[VONLFGHHHKMSRNPPNNMHG@EDHMT]cikkf]TQJECFLPSY^fcZUNHGKMQX\cba`YUPF=4205:CLU`gnlni^XRLKJPUX`ghjaXQLDA<?ELUX^_`c^WTI@;4/17=HNW[bcb[SOMNPTWaikmifaVLJGEEEHKPUTTVXSOJF?==ADKSWYYVQMIECCBIOR\cceed`]XXY]``abc_ZVQKJKHGMNSV[[\]]ZYTRORUWX\_ghjijc]VPKLJPW_gnnooljfc]Z[ZY_ceeihg`\XSVW]ahmw……„~xpib\XVZ]bjruxwvoikd`dgkt}†‡‰†€wpia^[^ciluz‚ˆ‡…|rmf_VW[`ins|~~zvqmjjmmw|ƒŠ‰…Š„}rnmmomu~‚Œ•›š—ƒwoecegglqsvzxyzxytst{€‚ˆ‹Œ‘‹‰†…ƒƒ……‹Ž‘’›šš”Š…‚€ƒ…„„|yyrnnsty‰“—•”’Œ‰…ƒ††…Œ•š››š•„yrolkos}~€„€}{{xvvwz†“–œ—’‡€vpsw‹“œ¥¬´±®¡™†~ytyz}€~}{tooifkjpw€‰–“…|piegku|‚‰’—š˜•…}womjflvy|€zupg\WWY\bky}‚†…ƒyrofghjrz…Ž‘••”Œ…{tjd`acgdfjga_YSOIJIRX[gkorppgca^`bhmsy„ˆ‹ŒŒ‹„{qkgd__^`^ZSNF@;0/0.4?ISX^ZXSLDBDEHQ\bfqsutnhebcabelmutsmhaQG?6+%&'-9CGFHJF=7358>LZbhouz}zunhaXUUSW[_dbdc`WLB>4/24:>>=>?7.$,<FR[emkkdbXRKGKJNSXWVSOIB?5/+,6>CDFGC;1&!#*4;BFIJIFD@?=?@AFGFFEFF@>5-%!!$(3??90& '.79=<942,&!$%%(.443.+%! ýÿ÷ÿúÿ *45796,&  óÿêÿèÿäÿâÿäÿåÿìÿõÿþÿ! ûÿøÿõÿóÿîÿèÿßÿÛÿ×ÿÜÿÞÿèÿîÿúÿ ÿÿîÿäÿÚÿÔÿÖÿÒÿÖÿáÿæÿëÿòÿùÿüÿÿÿÿÿÿÿúÿúÿöÿòÿïÿëÿãÿÝÿÖÿÐÿÅÿÆÿÊÿÎÿØÿÞÿæÿèÿçÿçÿßÿÜÿÕÿÏÿÌÿÊÿÌÿÔÿÛÿåÿëÿðÿóÿõÿòÿîÿëÿèÿãÿßÿÙÿÙÿÜÿßÿâÿèÿíÿèÿçÿêÿéÿåÿÛÿ×ÿÏÿÈÿÄÿÁÿÄÿÇÿÈÿÑÿÖÿÚÿÚÿÙÿÕÿËÿÅÿ½ÿºÿ»ÿ¾ÿÇÿÎÿÙÿÝÿäÿêÿðÿóÿóÿíÿèÿåÿàÿÛÿÛÿÝÿÝÿâÿãÿáÿÝÿÙÿÙÿÔÿÒÿÊÿÆÿÆÿÃÿ½ÿ¼ÿ¾ÿÂÿÅÿÇÿÍÿÑÿ×ÿÒÿÍÿÈÿÁÿ¼ÿ¸ÿ¼ÿ½ÿÂÿÈÿÒÿÜÿäÿêÿðÿòÿôÿôÿðÿèÿçÿäÿÚÿÝÿÛÿÛÿÝÿÛÿÚÿÛÿ×ÿÔÿÑÿÏÿÊÿÅÿÀÿ·ÿµÿ´ÿ´ÿ»ÿÆÿÍÿÐÿÕÿØÿÔÿÔÿÈÿ¼ÿµÿ®ÿ®ÿ¯ÿ³ÿ·ÿÃÿÊÿÖÿÝÿæÿçÿæÿçÿèÿæÿäÿßÿßÿáÿáÿåÿêÿçÿåÿãÿÛÿÔÿÍÿÊÿÂÿ·ÿ®ÿ§ÿ¡ÿœÿœÿŸÿ¤ÿªÿ¯ÿ¸ÿ½ÿÁÿÃÿÃÿÄÿÂÿÄÿÈÿÉÿÌÿØÿßÿåÿéÿïÿïÿêÿäÿàÿÚÿÔÿÑÿÑÿÏÿÏÿÕÿØÿßÿâÿáÿÜÿÜÿÛÿÖÿÓÿÍÿÇÿÁÿ¹ÿ¬ÿ­ÿ¬ÿ­ÿ±ÿµÿ³ÿ´ÿ²ÿ­ÿ¥ÿžÿ—ÿ‘ÿ–ÿ›ÿ¢ÿ®ÿ¿ÿÍÿÞÿëÿöÿûÿøÿøÿóÿíÿéÿãÿÛÿÜÿØÿÖÿÒÿÔÿÐÿÌÿÄÿÁÿ½ÿ¹ÿ´ÿµÿ¶ÿµÿ¶ÿ½ÿ¾ÿ¿ÿÆÿÇÿÆÿÇÿÅÿÃÿ»ÿ´ÿ­ÿ§ÿ£ÿŸÿ¡ÿ«ÿ¯ÿ´ÿ¿ÿÉÿÓÿØÿÝÿáÿâÿâÿåÿãÿáÿáÿãÿæÿãÿãÿäÿáÿÚÿÔÿÑÿÌÿÃÿÀÿ¹ÿ±ÿ¬ÿ¯ÿ°ÿ±ÿ·ÿ¿ÿÃÿÄÿÈÿÊÿÄÿÁÿÁÿ»ÿ½ÿÀÿÂÿÂÿÂÿÌÿ×ÿßÿéÿéÿìÿêÿìÿçÿãÿáÿâÿáÿâÿåÿìÿðÿïÿîÿêÿåÿÛÿÖÿÒÿÉÿ¿ÿ»ÿ·ÿ´ÿ¶ÿ¶ÿ¹ÿ½ÿÄÿÈÿÉÿÉÿÊÿÄÿ¿ÿ½ÿ¶ÿ·ÿºÿ½ÿÅÿÎÿÕÿÞÿèÿòÿùÿøÿùÿøÿñÿêÿäÿÜÿÙÿÞÿÞÿÛÿãÿäÿäÿáÿÝÿÖÿÓÿËÿÂÿ¼ÿ³ÿ«ÿ§ÿªÿ«ÿªÿ±ÿ³ÿ¸ÿ¸ÿ¸ÿ¶ÿ°ÿ«ÿ©ÿ£ÿ¦ÿ§ÿ°ÿ¼ÿÈÿ×ÿäÿîÿúÿþÿÿÿøÿòÿíÿéÿåÿáÿàÿÜÿÚÿÚÿÛÿÝÿ×ÿÑÿËÿÅÿ»ÿ³ÿ­ÿ­ÿ«ÿ«ÿªÿªÿ¬ÿ¯ÿ¸ÿ¶ÿ¸ÿ·ÿ³ÿ®ÿ¦ÿ¥ÿ¥ÿ¢ÿ¤ÿ§ÿ°ÿ¼ÿÈÿÑÿÜÿæÿïÿñÿóÿóÿðÿñÿóÿîÿìÿëÿïÿñÿïÿîÿðÿêÿáÿÙÿÏÿÆÿ¼ÿ¶ÿ®ÿªÿ£ÿ¢ÿ¢ÿ¦ÿ¦ÿ¦ÿ¥ÿ¨ÿ§ÿ¥ÿžÿžÿ¡ÿŸÿ ÿ§ÿ¯ÿ´ÿ¾ÿÍÿÓÿÛÿáÿäÿåÿåÿâÿÛÿÝÿßÿãÿéÿíÿðÿóÿðÿïÿéÿäÿßÿÙÿÒÿÍÿÄÿÃÿÁÿ¿ÿºÿºÿ¸ÿµÿµÿµÿ³ÿ³ÿ®ÿ©ÿ¤ÿ¥ÿ©ÿªÿ­ÿ²ÿ»ÿÄÿÏÿÝÿçÿòÿúÿùÿúÿöÿñÿíÿíÿíÿìÿíÿíÿïÿòÿïÿëÿèÿäÿÛÿÏÿÈÿÃÿ½ÿ¹ÿºÿ¸ÿ¸ÿ½ÿÂÿ½ÿ¼ÿ·ÿ²ÿ¯ÿ©ÿ¡ÿšÿ–ÿ“ÿ˜ÿÿ¨ÿ¶ÿÂÿÎÿÝÿåÿìÿòÿòÿìÿìÿçÿãÿãÿãÿäÿæÿèÿëÿìÿîÿíÿçÿÜÿÔÿÏÿÅÿ¿ÿ¸ÿ¶ÿ³ÿ¶ÿ³ÿºÿÀÿÄÿÉÿÉÿÍÿÄÿ»ÿ³ÿ©ÿ¢ÿÿÿ£ÿ­ÿºÿÅÿÓÿäÿïÿúÿýÿùÿùÿøÿöÿöÿûÿýÿøÿðÿâÿÖÿÊÿ¾ÿ´ÿªÿ¥ÿ¥ÿ¨ÿ®ÿ´ÿ¾ÿÆÿÊÿÈÿÈÿÂÿ½ÿ½ÿ¹ÿ»ÿºÿ¿ÿÇÿÏÿÜÿéÿõÿþÿüÿþÿþÿ ÿÿúÿðÿéÿâÿÙÿÒÿÎÿÊÿÄÿÂÿ¼ÿ»ÿ¶ÿ°ÿ­ÿ¯ÿ³ÿ´ÿ·ÿ½ÿÈÿÔÿàÿîÿúÿ $#"ùÿóÿêÿæÿçÿíÿòÿõÿõÿñÿñÿîÿèÿÞÿÕÿÊÿÆÿÅÿÃÿÉÿÉÿÓÿÝÿèÿòÿúÿ "#(.6:<>@=6,% þÿúÿøÿõÿôÿùÿúÿüÿùÿöÿîÿçÿáÿØÿÔÿÓÿÔÿÙÿäÿìÿøÿ #(-48=;=70'  òÿæÿÛÿÕÿÕÿ×ÿÖÿßÿíÿýÿ (351-&"!*148841-'"!  ùÿñÿîÿíÿîÿíÿñÿøÿ/6:<730*('*+*.2441/'  ýÿýÿøÿöÿôÿðÿôÿ÷ÿþÿ !+,.,-,,/144;60+'! þÿûÿúÿ÷ÿöÿùÿøÿùÿ÷ÿøÿóÿéÿàÿßÿÛÿØÿÙÿßÿàÿïÿùÿ $$$$! ûÿôÿîÿèÿåÿáÿÜÿßÿÞÿÚÿÝÿ×ÿÕÿÕÿÌÿÈÿÆÿÇÿÌÿÖÿÝÿèÿìÿûÿ ')($ûÿöÿëÿáÿßÿßÿàÿâÿãÿäÿãÿßÿÞÿÙÿÓÿÇÿ½ÿ¸ÿ¶ÿ¹ÿ¶ÿ»ÿÂÿÌÿÚÿìÿùÿ  ýÿóÿëÿäÿÙÿÒÿÏÿÓÿÓÿÓÿÛÿÜÿáÿãÿàÿÜÿÔÿÌÿÆÿ¾ÿ¿ÿÂÿÃÿÊÿÏÿÒÿÝÿçÿìÿõÿúÿúÿúÿøÿöÿ÷ÿûÿùÿéÿÞÿ×ÿÏÿËÿÇÿÀÿÃÿÄÿÇÿÈÿÊÿÊÿÅÿ¿ÿ¼ÿ¶ÿ·ÿ½ÿÁÿËÿÒÿÝÿçÿìÿöÿûÿýÿþÿûÿúÿùÿøÿïÿïÿõÿõÿüÿÿÿ þÿóÿîÿçÿÞÿÚÿÕÿÑÿÎÿÈÿÆÿÁÿÄÿÁÿ·ÿ®ÿ¤ÿŸÿšÿ˜ÿÿ¢ÿ¯ÿºÿÇÿÚÿæÿïÿùÿÿÿþÿ÷ÿôÿôÿóÿñÿñÿîÿñÿóÿòÿôÿóÿêÿåÿàÿÖÿÌÿÂÿÀÿ½ÿºÿºÿ»ÿºÿ¹ÿºÿ¬ÿ§ÿ£ÿžÿ•ÿ•ÿ’ÿ–ÿ¡ÿ«ÿ²ÿ¼ÿÅÿÑÿÙÿÜÿâÿêÿíÿðÿðÿòÿòÿùÿÿÿ üÿîÿåÿàÿÛÿÐÿÈÿÄÿ¿ÿÁÿ¾ÿ½ÿºÿ¶ÿ¯ÿ¥ÿÿÿ‰ÿ…ÿ…ÿˆÿ’ÿ›ÿ¦ÿ³ÿÀÿÌÿÔÿßÿãÿãÿæÿèÿåÿÜÿ×ÿÙÿÜÿÞÿçÿñÿöÿþÿùÿíÿèÿßÿÖÿÎÿËÿÇÿÃÿÃÿÅÿÃÿ¾ÿ»ÿµÿ«ÿ¡ÿ™ÿ’ÿŽÿ’ÿšÿ¤ÿ±ÿÁÿÊÿÓÿØÿáÿåÿåÿäÿäÿßÿÞÿÞÿÝÿÚÿâÿëÿòÿøÿþÿÿÿøÿîÿåÿßÿÛÿÙÿÒÿÑÿÒÿÐÿÎÿÎÿÅÿ¿ÿµÿ©ÿ ÿžÿ˜ÿšÿ¡ÿ©ÿ·ÿÅÿ×ÿäÿíÿöÿúÿýÿþÿúÿöÿòÿëÿæÿåÿèÿìÿðÿúÿüÿþÿúÿöÿìÿèÿäÿäÿÝÿÜÿØÿ×ÿØÿÔÿÑÿÍÿÆÿºÿ°ÿ­ÿªÿ¬ÿ²ÿ¹ÿÅÿÒÿßÿêÿõÿ þÿÿÿ  ÿÿøÿòÿêÿãÿâÿÞÿÚÿÝÿÛÿÛÿÞÿÚÿÖÿÍÿÄÿ½ÿºÿ½ÿÀÿÉÿÔÿáÿíÿúÿ  ùÿ÷ÿôÿðÿîÿëÿéÿàÿÙÿÐÿÇÿÀÿ¼ÿ¼ÿ¾ÿÅÿÕÿáÿîÿÿÿ'0/-*(&""&-146652-%ÿÿÿÿüÿõÿîÿãÿÖÿÈÿ»ÿ¶ÿ²ÿ¸ÿÀÿÍÿÝÿíÿ"$(++$# #%(*&! ýÿøÿùÿýÿüÿúÿüÿüÿöÿçÿÜÿÎÿ¿ÿ¹ÿ³ÿ±ÿµÿÁÿÏÿßÿíÿüÿ "þÿôÿêÿçÿâÿßÿáÿâÿäÿâÿÚÿÖÿÌÿÅÿºÿ°ÿ¬ÿ§ÿ¥ÿ­ÿ¹ÿÈÿÖÿãÿïÿøÿÿÿÿÿýÿûÿúÿüÿúÿúÿýÿÿÿùÿõÿïÿéÿãÿÞÿÙÿÔÿÒÿÏÿËÿÇÿÁÿ¹ÿ¬ÿ¢ÿœÿ˜ÿ˜ÿÿ©ÿ³ÿºÿÄÿÍÿØÿàÿìÿóÿøÿøÿùÿôÿïÿêÿêÿêÿéÿëÿïÿóÿ÷ÿùÿôÿóÿóÿïÿèÿàÿÜÿÒÿÎÿÉÿÇÿÇÿÇÿÆÿÄÿ¹ÿ²ÿªÿ£ÿ˜ÿÿ‡ÿ‡ÿ†ÿÿšÿªÿ³ÿ¿ÿÍÿÚÿÛÿçÿëÿíÿîÿóÿðÿòÿñÿïÿíÿîÿðÿñÿóÿñÿîÿîÿìÿáÿÜÿÙÿÓÿÍÿËÿÇÿÆÿÉÿÉÿÆÿÀÿ¸ÿ¬ÿžÿ“ÿŒÿ…ÿƒÿ‰ÿÿ›ÿ¦ÿ²ÿÃÿËÿ×ÿÛÿäÿäÿäÿàÿÝÿÚÿÙÿÖÿÙÿØÿßÿåÿìÿïÿóÿöÿöÿ÷ÿôÿòÿèÿâÿØÿÔÿÓÿÏÿËÿÎÿÌÿËÿÄÿ¾ÿ±ÿ¥ÿ˜ÿÿ†ÿ„ÿˆÿÿ—ÿ¥ÿ´ÿÃÿÏÿ×ÿãÿéÿìÿíÿíÿëÿäÿáÿÜÿÙÿÛÿâÿçÿëÿðÿóÿôÿôÿôÿîÿæÿáÿÜÿÖÿÌÿËÿÈÿÌÿËÿÍÿÏÿÊÿÆÿºÿ²ÿ£ÿ™ÿ—ÿ”ÿ“ÿÿªÿ³ÿÃÿÒÿÞÿêÿïÿõÿûÿúÿ÷ÿöÿòÿïÿêÿåÿáÿßÿàÿâÿéÿîÿñÿøÿûÿùÿöÿöÿôÿîÿëÿçÿßÿÛÿÖÿÖÿÏÿÈÿ¿ÿµÿ¬ÿ£ÿ¢ÿÿœÿ ÿ§ÿ´ÿÄÿÒÿâÿïÿûÿ ýÿûÿñÿêÿçÿâÿÛÿÜÿÞÿßÿàÿäÿæÿâÿâÿáÿßÿÞÿÞÿßÿàÿàÿàÿäÿãÿÞÿÚÿÑÿÄÿ¹ÿ«ÿ¤ÿ ÿžÿžÿ¤ÿ­ÿ¹ÿÃÿÕÿáÿðÿýÿ üÿøÿöÿòÿïÿòÿöÿòÿóÿîÿìÿêÿëÿìÿêÿæÿâÿÝÿÙÿØÿÝÿÙÿÑÿÉÿÀÿ·ÿ°ÿ«ÿ¥ÿ¥ÿ¨ÿ®ÿ¸ÿÄÿÑÿßÿêÿóÿýÿ þÿõÿðÿëÿéÿåÿçÿåÿãÿâÿäÿäÿáÿßÿØÿÉÿ¼ÿ­ÿžÿ–ÿ—ÿ“ÿ˜ÿ ÿ­ÿºÿÊÿÚÿêÿ÷ÿ  ÿÿýÿúÿøÿøÿùÿøÿóÿôÿôÿóÿñÿïÿéÿäÿßÿÞÿßÿàÿàÿàÿØÿÙÿÔÿËÿÂÿ´ÿ¨ÿÿ–ÿ”ÿ–ÿœÿŸÿ«ÿ³ÿÁÿÇÿÓÿàÿæÿíÿñÿíÿîÿèÿæÿåÿèÿçÿéÿíÿóÿöÿùÿùÿùÿôÿîÿéÿæÿÞÿÙÿ×ÿ×ÿ×ÿÐÿÐÿÐÿÒÿÏÿÌÿÅÿ¼ÿ±ÿ©ÿ¡ÿžÿœÿ¡ÿ§ÿ³ÿ¾ÿÇÿÐÿÚÿåÿéÿíÿðÿïÿîÿëÿíÿèÿãÿÞÿàÿâÿãÿáÿãÿâÿàÿßÿÝÿÕÿÔÿÖÿÕÿÖÿØÿ×ÿ×ÿÝÿÜÿÙÿÓÿÎÿ¿ÿ´ÿ§ÿ§ÿ§ÿ¦ÿ¤ÿ¯ÿ³ÿ¸ÿÁÿÒÿÛÿåÿðÿùÿÿÿÿÿþÿýÿùÿõÿðÿíÿéÿìÿïÿïÿòÿóÿðÿðÿïÿîÿèÿéÿàÿÛÿØÿØÿÔÿÑÿÏÿÐÿÐÿÑÿÌÿÄÿÃÿÂÿ¼ÿÀÿÈÿÎÿÑÿÙÿáÿåÿêÿñÿõÿ÷ÿüÿÿÿ÷ÿóÿïÿïÿëÿæÿâÿáÿáÿÞÿàÿÞÿ×ÿÓÿÊÿÀÿ·ÿ³ÿ±ÿ¯ÿ±ÿºÿÅÿÓÿãÿïÿõÿýÿ   þÿüÿùÿðÿðÿñÿðÿíÿëÿíÿæÿãÿÜÿÕÿÉÿ¾ÿµÿ°ÿ¦ÿ¥ÿ©ÿ±ÿºÿÃÿÑÿÜÿéÿöÿ   üÿöÿöÿõÿòÿôÿöÿ÷ÿõÿöÿóÿïÿåÿÛÿÐÿÄÿ¸ÿ³ÿ¯ÿ¬ÿ³ÿ¸ÿ¾ÿÊÿÓÿàÿíÿúÿ   ÿÿÿÿ þÿúÿðÿäÿÚÿÑÿÍÿÆÿÂÿÄÿÈÿÏÿØÿàÿéÿøÿ !""!  þÿúÿûÿ÷ÿøÿúÿþÿüÿòÿíÿäÿØÿÕÿÑÿÏÿÐÿÖÿàÿêÿðÿøÿ !',-,&! þÿüÿïÿãÿÙÿÑÿÉÿÅÿÆÿÅÿÏÿÛÿæÿîÿõÿüÿ!  ÿÿûÿôÿñÿðÿöÿúÿÿÿúÿïÿåÿÝÿÕÿÒÿÖÿØÿÞÿãÿíÿôÿ#&'*-.+..-,'$ûÿ÷ÿ÷ÿûÿüÿýÿ ùÿïÿäÿãÿÞÿÛÿÜÿâÿçÿõÿýÿ !###$$ &+/44874/'  ÷ÿòÿõÿòÿöÿ $)--//0.)'&',1/20..0.)! øÿóÿíÿëÿçÿéÿñÿõÿÿÿ !(.05689452.1442.)%$"üÿôÿíÿíÿôÿúÿ'-67<=>CCCA??>8<51-'üÿöÿóÿïÿòÿöÿýÿ #+/37;>@=>::7787541,% ÿÿøÿìÿéÿçÿîÿõÿþÿ"$'+++15489;>A>>B>7/, ûÿðÿêÿæÿàÿáÿæÿïÿùÿ$)('$&**),*,-.+%þÿþÿÿÿ  ûÿôÿïÿçÿçÿæÿëÿðÿóÿøÿþÿ õÿìÿçÿæÿäÿéÿêÿðÿôÿöÿòÿðÿæÿßÿØÿÏÿÐÿÕÿÛÿÜÿãÿëÿõÿùÿ    ýÿôÿîÿêÿæÿçÿéÿëÿéÿîÿðÿðÿæÿäÿßÿÕÿÎÿÏÿÕÿÛÿâÿêÿôÿÿÿ      üÿòÿìÿèÿäÿâÿäÿáÿäÿêÿìÿéÿçÿãÿÙÿÏÿÄÿÅÿÄÿÅÿÉÿÎÿÛÿåÿðÿûÿ  üÿôÿøÿøÿüÿûÿýÿÿÿøÿïÿåÿÞÿßÿßÿâÿæÿéÿóÿöÿûÿ$%&('-135761,$ ûÿøÿ÷ÿøÿúÿþÿþÿõÿôÿóÿñÿôÿ÷ÿþÿ"++,*-010215458<74,'  ûÿ÷ÿøÿûÿ$)03477<;766;;<?=@><==;54-% *09@BEIKMKHDE@@FF@=>:30&!  #).6::ALMNLLIGDAA>@>;<72-! ûÿøÿõÿòÿðÿðÿìÿéÿæÿãÿßÿßÿäÿìÿöÿ"$$#%&*&'+/.01..'# ÿÿöÿñÿéÿäÿãÿâÿÛÿàÿÝÿÖÿÍÿÉÿÃÿ¿ÿºÿ¼ÿÃÿÏÿÛÿèÿñÿûÿ   ÿÿúÿòÿìÿçÿßÿÛÿÔÿÑÿÐÿÎÿÈÿ¿ÿ¶ÿ®ÿ¥ÿŸÿÿžÿ£ÿ´ÿÄÿÍÿÙÿãÿðÿûÿ ÿÿÿÿûÿøÿóÿîÿèÿáÿÝÿÖÿÔÿ×ÿÕÿÑÿÚÿØÿ×ÿÍÿÄÿ¼ÿ±ÿ§ÿžÿ—ÿ”ÿœÿ¤ÿ¬ÿ³ÿ½ÿÇÿÑÿßÿæÿêÿïÿöÿøÿöÿûÿûÿüÿþÿþÿþÿøÿ÷ÿîÿçÿàÿÖÿËÿÈÿÅÿÁÿÀÿÆÿÇÿÊÿÈÿÈÿÁÿ¸ÿ²ÿ¬ÿ¥ÿ£ÿ¥ÿªÿ°ÿ·ÿÃÿÉÿÌÿÒÿÛÿáÿæÿîÿîÿíÿïÿðÿïÿðÿîÿíÿðÿïÿñÿöÿöÿõÿôÿîÿèÿäÿßÿÚÿËÿÇÿÄÿÁÿ¼ÿ¹ÿµÿµÿ°ÿ¨ÿ¢ÿžÿšÿ›ÿŸÿ¥ÿ­ÿ¶ÿ»ÿÃÿÌÿËÿÎÿÓÿ×ÿÞÿãÿæÿèÿèÿçÿéÿëÿìÿïÿðÿòÿîÿïÿêÿæÿâÿàÿÜÿÚÿÕÿÒÿÍÿÉÿÌÿËÿÈÿÃÿÁÿ½ÿºÿ²ÿ®ÿ¨ÿ£ÿ¢ÿ¨ÿ®ÿ¸ÿÂÿÉÿÒÿÒÿÕÿØÿÜÿàÿàÿâÿãÿåÿçÿëÿëÿìÿëÿîÿñÿñÿòÿîÿèÿçÿåÿàÿÙÿ×ÿÐÿÍÿÈÿÅÿÀÿÁÿ¿ÿ½ÿ»ÿ²ÿ±ÿ«ÿ¥ÿ¢ÿ¢ÿ§ÿ«ÿ®ÿ¶ÿ¼ÿÅÿÊÿÒÿÔÿ×ÿÕÿÜÿÜÿáÿäÿèÿíÿíÿòÿ÷ÿøÿøÿ÷ÿøÿöÿðÿîÿêÿêÿâÿÜÿÕÿÒÿÏÿÌÿÍÿÌÿÌÿËÿÍÿÆÿ¼ÿµÿ±ÿ­ÿ¨ÿ¨ÿ¯ÿ±ÿ»ÿÃÿÈÿËÿÍÿÑÿÖÿØÿÛÿÛÿÙÿÚÿÚÿàÿÞÿæÿçÿîÿóÿõÿüÿûÿøÿøÿùÿúÿóÿïÿëÿæÿãÿÞÿÛÿÖÿÑÿÍÿËÿÊÿÇÿÂÿÀÿÁÿ¹ÿ¶ÿµÿ¸ÿ¿ÿÅÿÍÿÓÿÞÿåÿêÿëÿñÿîÿêÿíÿðÿìÿìÿêÿëÿæÿäÿèÿêÿëÿëÿîÿñÿôÿ÷ÿ÷ÿöÿòÿëÿéÿäÿâÿÞÿÞÿÙÿ×ÿÓÿÉÿÂÿÁÿºÿ·ÿºÿ½ÿÄÿÍÿ×ÿÞÿàÿãÿçÿíÿñÿ÷ÿúÿüÿûÿûÿûÿûÿýÿøÿ÷ÿùÿ÷ÿ÷ÿ÷ÿöÿ÷ÿöÿöÿóÿôÿðÿïÿíÿëÿðÿïÿêÿèÿãÿàÿÚÿÚÿÔÿÐÿÑÿÒÿÒÿÓÿ×ÿßÿæÿðÿõÿöÿùÿþÿÿÿ     ÿÿûÿûÿûÿúÿ÷ÿóÿðÿðÿðÿîÿéÿáÿâÿæÿåÿêÿòÿüÿ ÿÿþÿùÿòÿîÿëÿéÿèÿåÿãÿéÿðÿ÷ÿüÿ$'+-11543/0.,.-+)$$#! ýÿÿÿ "(035;<@?@>@=<:963.-.+$$%" ýÿùÿûÿÿÿ #(04;==@FDFIIKKIB<:740,,-( !  ÿÿÿÿ"$&.5:76:;?@BEFGGGF?;82,*%#"ýÿøÿôÿòÿôÿÿÿ (+038==?BDCDHHHDFCA<=<941/-& ÿÿøÿõÿøÿûÿüÿÿÿ!',05:??EILOOSSSRNGFA=71.*''$&##" þÿýÿ ",5<:?@DFGKHLQPMKFFGCC>6442+)% !',16489:>@?BFJKNTPLLE><653//-)%%  ýÿÿÿ&*.2488:<>ADGIIIEGB=9773+**(*)%  ÿÿûÿûÿ  (378:<;7;=>=BA?@>;;:87652-+.)+*$ ýÿùÿûÿÿÿ !))/23646=>@CELQRQOME>61+'## ùÿôÿõÿöÿøÿùÿÿÿ "%+12466567:<CC?A?<43/.*+,'##  !#(-18678;AC?AEDFB>9;43222-)% þÿüÿõÿôÿøÿúÿþÿ   &,+14533573+-)*)''(''$ûÿ÷ÿøÿûÿþÿ  $&%%))-0231/))*##$#!"#!&$  "$,,/10,-+*('%(,*)/,,+*$#  ÿÿûÿùÿøÿøÿÿÿ !##%)'%##%###%&## ÿÿÿÿúÿüÿ÷ÿòÿñÿîÿæÿâÿÜÿÝÿÝÿáÿëÿïÿòÿ÷ÿúÿÿÿ  ÿÿüÿúÿ÷ÿ÷ÿôÿðÿëÿæÿàÿ×ÿÑÿÒÿÌÿËÿÌÿÑÿÔÿÛÿàÿæÿéÿîÿöÿûÿþÿ   ýÿüÿ÷ÿöÿòÿðÿõÿôÿðÿñÿîÿïÿèÿæÿåÿÞÿÖÿÍÿÌÿÈÿÆÿÇÿÇÿÏÿÔÿ×ÿÜÿãÿèÿèÿéÿëÿêÿíÿóÿøÿöÿùÿþÿ ûÿýÿüÿùÿøÿøÿõÿòÿñÿîÿêÿäÿâÿÝÿÒÿÍÿÌÿÏÿÒÿÒÿÖÿÝÿàÿâÿãÿáÿßÿàÿáÿáÿåÿãÿåÿåÿæÿëÿïÿðÿóÿõÿöÿõÿóÿñÿíÿíÿìÿçÿâÿßÿÜÿÝÿÝÿàÿàÿÝÿàÿÞÿÝÿÙÿÓÿÏÿÄÿ½ÿ¿ÿ¿ÿÄÿÈÿÎÿÐÿÓÿØÿÙÿÜÿÜÿáÿåÿèÿëÿêÿëÿíÿìÿðÿòÿñÿñÿïÿìÿëÿèÿåÿçÿèÿæÿãÿàÿÜÿÚÿÜÿ×ÿÙÿÑÿËÿÈÿÅÿÂÿ¾ÿ¶ÿ³ÿ·ÿ¸ÿ¸ÿ¾ÿÂÿÈÿÎÿÖÿÔÿØÿ×ÿÚÿ×ÿ×ÿÙÿÞÿßÿÞÿÜÿàÿáÿßÿåÿçÿæÿäÿâÿâÿÞÿØÿØÿÓÿÒÿÎÿËÿËÿËÿÌÿËÿÌÿËÿÈÿÇÿÁÿ»ÿ²ÿ±ÿ±ÿ´ÿ·ÿ¼ÿÇÿÊÿÊÿËÿÏÿ×ÿÔÿÕÿÔÿÙÿßÿáÿæÿéÿéÿäÿäÿæÿëÿêÿèÿäÿæÿâÿãÿÞÿÛÿØÿÖÿÒÿÌÿÇÿÉÿÆÿÄÿÂÿÀÿ¼ÿµÿ°ÿ§ÿ¢ÿ£ÿ¢ÿ¢ÿ§ÿ¨ÿ®ÿ·ÿ¹ÿ¼ÿÂÿÆÿÌÿÌÿÕÿÓÿÖÿÛÿÚÿÝÿÞÿÛÿÞÿÙÿÖÿÔÿÏÿÎÿÊÿËÿÍÿÏÿÐÿÒÿÓÿÐÿÐÿÑÿÎÿÉÿÅÿÅÿ¼ÿºÿ±ÿ«ÿ¨ÿ ÿœÿšÿœÿœÿÿ£ÿ¨ÿªÿ±ÿ°ÿ±ÿ´ÿ»ÿ½ÿ¾ÿÁÿÇÿÈÿÍÿÏÿÓÿÑÿÑÿÉÿÇÿÄÿ¾ÿ¹ÿµÿ´ÿµÿ¶ÿ´ÿ¶ÿµÿ¶ÿ³ÿ¯ÿ®ÿ§ÿ¦ÿ¢ÿ›ÿ”ÿŽÿŠÿ‰ÿŠÿ‰ÿÿ’ÿ–ÿžÿœÿœÿ ÿŸÿ¢ÿ¤ÿ¥ÿ¢ÿ¡ÿ¦ÿ¦ÿ¦ÿ«ÿ´ÿ´ÿ·ÿ¶ÿ·ÿ°ÿªÿ©ÿ¨ÿ¦ÿ¢ÿ¤ÿ¦ÿªÿ¨ÿ§ÿ¥ÿ¤ÿ¡ÿÿšÿ–ÿ”ÿ“ÿ‘ÿ‹ÿ‰ÿˆÿ„ÿÿƒÿ…ÿ‰ÿŒÿŽÿÿÿ‘ÿ“ÿ’ÿ”ÿ–ÿšÿ¡ÿ¤ÿ§ÿ¬ÿ°ÿ°ÿ°ÿ®ÿ­ÿ©ÿ¤ÿŸÿ›ÿ˜ÿ‘ÿ‘ÿ“ÿ”ÿ”ÿ–ÿšÿÿšÿšÿ™ÿ˜ÿ˜ÿ”ÿŽÿ‡ÿˆÿ†ÿ†ÿ‹ÿÿ•ÿ–ÿ•ÿšÿ™ÿ˜ÿšÿÿÿœÿžÿ ÿ£ÿ¨ÿ¬ÿ°ÿ³ÿ¶ÿ³ÿ²ÿ°ÿ²ÿ«ÿ§ÿ¦ÿ¦ÿ©ÿ«ÿ©ÿ¨ÿ£ÿ§ÿ¥ÿ¢ÿ¡ÿ›ÿ›ÿŸÿÿ¡ÿ˜ÿ˜ÿ–ÿ—ÿ™ÿœÿžÿŸÿ¦ÿ¦ÿ¤ÿ¥ÿ¥ÿ©ÿ§ÿ¨ÿ¯ÿ´ÿµÿµÿ½ÿÂÿÃÿÁÿÂÿÁÿÀÿ¾ÿ¸ÿµÿ¶ÿµÿ³ÿ°ÿ²ÿ³ÿ°ÿ®ÿ¬ÿ¬ÿ¯ÿ­ÿ¬ÿ¦ÿ¦ÿ¢ÿŸÿ™ÿÿžÿ¦ÿ©ÿ­ÿ²ÿ´ÿºÿ¼ÿ»ÿ¹ÿ¹ÿºÿ¼ÿ¸ÿºÿ¼ÿÁÿÀÿÅÿËÿÊÿÊÿËÿÌÿÍÿÎÿËÿÈÿÃÿÀÿ½ÿ¿ÿÂÿÂÿÂÿÄÿ¿ÿÀÿ¿ÿ¾ÿ¼ÿ»ÿ·ÿ³ÿ²ÿ¯ÿ°ÿµÿ´ÿ»ÿÂÿÈÿÊÿÏÿÑÿÑÿÐÿÓÿÐÿÏÿÓÿØÿÚÿáÿáÿàÿÝÿÛÿÛÿ×ÿØÿÓÿÐÿËÿÍÿÐÿÔÿÔÿÖÿÓÿÒÿÉÿÈÿÊÿÈÿÃÿÄÿ¾ÿ¸ÿ·ÿ³ÿ¯ÿ®ÿ¯ÿ±ÿ¶ÿºÿÂÿÌÿÓÿÙÿÛÿàÿàÿßÿÝÿãÿåÿèÿëÿîÿíÿëÿíÿîÿíÿëÿäÿÞÿÚÿ×ÿÔÿ×ÿØÿØÿÜÿÛÿÞÿÙÿØÿÔÿÒÿÎÿÉÿÁÿ¿ÿ¼ÿ¹ÿ¶ÿ´ÿµÿ¸ÿ»ÿÁÿÈÿÎÿÐÿÖÿÕÿÚÿÝÿåÿäÿèÿêÿìÿïÿðÿöÿûÿýÿûÿùÿöÿñÿíÿæÿàÿØÿ×ÿÖÿ×ÿ×ÿÛÿÙÿÙÿÜÿÛÿÚÿÔÿÖÿÐÿÎÿÍÿÈÿÅÿÈÿÈÿÊÿÌÿÐÿØÿÜÿÙÿàÿÛÿÜÿÝÿâÿèÿíÿðÿôÿûÿ ÿÿ÷ÿóÿëÿæÿàÿâÿáÿàÿâÿÞÿàÿÞÿàÿÞÿÙÿÔÿÏÿËÿÅÿ¿ÿ¸ÿµÿ±ÿµÿ¹ÿ¾ÿÂÿÉÿÉÿÉÿÌÿÑÿÑÿÐÿÔÿÚÿÝÿáÿãÿèÿíÿðÿóÿùÿõÿôÿïÿêÿåÿßÿÚÿÙÿÖÿÓÿÓÿ×ÿ×ÿÖÿÔÿÖÿØÿÚÿÜÿÖÿÔÿÐÿËÿÃÿÄÿÄÿÆÿÈÿÎÿÓÿÕÿÕÿÚÿ×ÿÔÿÕÿÕÿÓÿØÿßÿäÿëÿòÿóÿõÿöÿöÿùÿ÷ÿöÿñÿèÿçÿáÿàÿáÿáÿàÿáÿÝÿÜÿÕÿÒÿÐÿÍÿÎÿËÿÇÿÇÿÄÿÆÿÊÿÏÿÒÿÔÿØÿâÿäÿáÿáÿãÿãÿàÿÜÿÚÿÝÿßÿàÿäÿêÿïÿòÿôÿ÷ÿñÿïÿìÿèÿâÿÜÿÛÿÖÿÕÿ×ÿÖÿÙÿÜÿßÿÞÿÜÿØÿØÿÔÿÒÿÐÿÍÿÌÿÊÿÐÿÕÿàÿçÿëÿïÿóÿ÷ÿ÷ÿóÿñÿïÿïÿëÿïÿñÿñÿøÿýÿÿÿýÿùÿöÿïÿïÿëÿëÿêÿíÿêÿçÿäÿãÿàÿâÿáÿÝÿ×ÿÒÿÑÿÑÿÑÿÔÿÕÿÛÿçÿðÿùÿüÿÿÿÿÿ ÿÿüÿüÿüÿýÿýÿúÿùÿ÷ÿóÿôÿïÿìÿçÿãÿÛÿÓÿÎÿÌÿÉÿÏÿÛÿãÿíÿøÿ #%'0/-'$ úÿ÷ÿöÿòÿðÿìÿçÿâÿâÿäÿåÿëÿñÿóÿùÿûÿÿÿ  $')+&%! ýÿûÿóÿìÿéÿçÿâÿßÿãÿæÿíÿòÿùÿ $&()(&! ûÿøÿøÿõÿñÿñÿðÿôÿúÿýÿ $),# ûÿ÷ÿøÿöÿøÿûÿ ! þÿÿÿ  üÿøÿöÿòÿðÿóÿúÿ  #'&%&$  üÿúÿóÿðÿðÿðÿóÿóÿ÷ÿþÿ " %')($!    ÿÿ÷ÿôÿñÿòÿóÿøÿ÷ÿ $),-.,/'! ÿÿùÿõÿôÿïÿñÿùÿýÿ !#)$(*-($# ÿÿþÿüÿúÿ÷ÿüÿÿÿ $$())#  ÿÿýÿúÿþÿ $)*%''%!$'$$& ýÿöÿóÿðÿóÿöÿùÿüÿÿÿ ûÿýÿøÿ÷ÿ÷ÿûÿþÿüÿúÿøÿóÿíÿìÿìÿëÿïÿõÿýÿ  ÿÿûÿ÷ÿôÿöÿ÷ÿõÿüÿýÿùÿôÿíÿãÿÝÿÚÿÕÿÔÿ×ÿÞÿäÿîÿöÿ   úÿøÿòÿîÿíÿéÿçÿçÿäÿèÿìÿëÿëÿëÿðÿñÿðÿíÿìÿèÿäÿÞÿØÿÖÿÒÿÓÿÔÿÙÿÛÿßÿäÿëÿíÿñÿóÿñÿôÿóÿñÿôÿðÿðÿðÿøÿùÿûÿöÿðÿïÿëÿàÿÙÿÖÿÒÿÔÿÔÿÔÿ×ÿÚÿßÿáÿåÿãÿàÿÞÿÕÿÎÿËÿÆÿÃÿÂÿÃÿÄÿÉÿÐÿÕÿ×ÿßÿæÿêÿêÿëÿïÿïÿòÿòÿïÿõÿõÿõÿöÿùÿ÷ÿñÿëÿãÿÝÿÖÿÑÿÉÿÄÿÆÿÇÿÇÿÇÿÍÿÑÿÓÿÕÿ×ÿÕÿÎÿÌÿÆÿ»ÿ·ÿ´ÿ±ÿ¯ÿ±ÿ»ÿÀÿÆÿËÿÑÿÚÿÛÿÞÿäÿåÿãÿäÿäÿãÿçÿèÿåÿäÿäÿãÿâÿÛÿØÿÔÿÑÿÌÿÌÿÎÿÌÿÊÿÆÿÇÿÈÿÅÿÉÿÊÿÌÿËÿÉÿÆÿÁÿºÿµÿ³ÿ­ÿ°ÿ¸ÿ»ÿÂÿËÿÏÿÕÿÚÿÞÿäÿçÿêÿëÿëÿìÿòÿôÿñÿóÿóÿôÿöÿôÿïÿêÿãÿÝÿÛÿÙÿ×ÿÛÿÚÿÛÿÞÿâÿäÿãÿàÿáÿàÿÜÿÕÿÏÿÆÿÃÿÃÿÅÿÄÿÄÿÇÿÐÿÒÿÚÿâÿéÿêÿìÿñÿõÿúÿøÿøÿøÿüÿÿÿþÿÿÿýÿüÿøÿïÿëÿëÿëÿíÿíÿîÿóÿöÿüÿýÿþÿúÿöÿðÿëÿãÿØÿ×ÿÓÿÏÿÎÿÑÿÔÿÙÿáÿæÿèÿñÿøÿùÿüÿüÿúÿûÿùÿùÿùÿþÿûÿÿÿûÿþÿùÿõÿðÿïÿðÿòÿöÿùÿüÿÿÿ þÿùÿöÿìÿèÿåÿåÿâÿåÿæÿêÿðÿõÿøÿÿÿ  ÿÿûÿøÿúÿ÷ÿüÿ  ûÿùÿùÿýÿ !"  !!  !  ÿÿ !&/4::;7:740/*$    !')'**,,/123241+$  üÿøÿñÿðÿëÿëÿðÿðÿöÿüÿûÿ  !#&# ÷ÿôÿóÿ÷ÿöÿ÷ÿýÿ ôÿêÿäÿÞÿØÿÓÿØÿÚÿÜÿåÿíÿñÿ÷ÿøÿùÿúÿüÿüÿþÿûÿüÿøÿõÿóÿóÿîÿçÿäÿåÿåÿæÿéÿèÿìÿíÿóÿõÿóÿòÿîÿéÿäÿáÿÜÿ×ÿÔÿÑÿÒÿÔÿØÿÜÿàÿáÿäÿéÿìÿôÿöÿöÿ÷ÿúÿýÿúÿýÿüÿôÿóÿóÿîÿìÿèÿãÿàÿàÿßÿÝÿÞÿàÿãÿâÿåÿèÿèÿåÿæÿãÿÝÿÖÿÔÿÓÿÒÿÓÿØÿÜÿßÿâÿåÿéÿîÿóÿôÿñÿñÿñÿóÿïÿïÿìÿòÿñÿíÿðÿïÿêÿãÿßÿÜÿ×ÿÔÿÏÿÌÿÏÿÐÿÑÿÓÿÚÿÞÿÞÿßÿÞÿÝÿÛÿÒÿÑÿÐÿÐÿÉÿÄÿ¿ÿÈÿÎÿÑÿÔÿØÿÝÿäÿæÿêÿîÿñÿðÿíÿíÿïÿïÿîÿïÿîÿíÿéÿçÿâÿÜÿ×ÿÏÿÍÿÊÿÇÿÉÿÌÿÐÿÒÿÖÿÜÿßÿáÿÞÿÚÿÖÿÏÿÍÿÈÿÂÿÃÿÇÿÊÿËÿÑÿ×ÿÛÿäÿìÿîÿïÿîÿðÿòÿ÷ÿôÿòÿõÿøÿøÿùÿùÿüÿúÿôÿõÿòÿïÿæÿâÿÞÿÛÿÙÿÙÿÚÿÞÿâÿäÿæÿåÿåÿâÿÚÿÒÿÏÿÅÿ½ÿ½ÿ¿ÿÂÿÆÿÐÿÔÿÜÿáÿäÿíÿöÿùÿøÿõÿöÿøÿöÿôÿóÿñÿôÿöÿõÿóÿïÿïÿêÿäÿäÿàÿÛÿÜÿÙÿÜÿÚÿÛÿàÿáÿàÿèÿíÿæÿåÿåÿáÿÙÿ×ÿÕÿÒÿÏÿÐÿÎÿÔÿÚÿâÿæÿëÿóÿüÿ  ýÿûÿöÿòÿîÿïÿïÿíÿïÿïÿôÿóÿðÿòÿóÿñÿìÿçÿãÿáÿÛÿÜÿÝÿáÿâÿæÿèÿíÿîÿñÿøÿúÿúÿþÿ ûÿòÿîÿìÿñÿðÿñÿôÿöÿüÿþÿüÿóÿèÿãÿáÿßÿßÿáÿãÿãÿêÿîÿóÿøÿýÿ  þÿöÿöÿðÿëÿêÿéÿéÿìÿïÿíÿóÿöÿùÿøÿùÿøÿðÿëÿçÿåÿäÿæÿåÿëÿïÿóÿùÿúÿÿÿÿÿ  üÿúÿúÿøÿûÿüÿ  ùÿòÿæÿßÿÜÿßÿáÿãÿêÿôÿýÿ  þÿúÿ÷ÿõÿòÿòÿøÿüÿûÿÿÿûÿùÿóÿðÿêÿèÿèÿèÿéÿíÿòÿúÿ    $þÿùÿöÿðÿòÿòÿóÿóÿùÿúÿ "! $)),*'  ûÿüÿõÿôÿõÿùÿùÿ÷ÿùÿýÿ   ûÿøÿóÿñÿóÿõÿùÿ     ÷ÿõÿôÿöÿõÿõÿüÿûÿ   ÿÿüÿûÿýÿþÿýÿúÿöÿóÿõÿöÿöÿûÿþÿüÿôÿìÿéÿåÿßÿÜÿÝÿÛÿßÿåÿçÿíÿñÿùÿûÿýÿýÿùÿøÿøÿ÷ÿñÿíÿëÿèÿäÿàÿáÿÜÿÚÿ×ÿØÿÛÿÛÿßÿßÿäÿæÿçÿäÿßÿÞÿÝÿÙÿÖÿÔÿÒÿÒÿÔÿÓÿÕÿÓÿÕÿÙÿÛÿÝÿÜÿÞÿáÿåÿçÿæÿçÿêÿíÿèÿæÿåÿàÿ×ÿ×ÿÕÿÖÿÖÿÑÿÊÿÈÿÈÿÇÿÅÿÆÿÈÿÌÿÎÿÌÿËÿÍÿËÿÇÿ¾ÿ¾ÿ·ÿµÿµÿ´ÿ·ÿ»ÿ¾ÿÅÿÅÿÈÿÌÿÌÿÍÿÍÿÏÿÏÿÕÿÔÿÔÿÕÿÔÿÑÿÐÿÌÿÆÿÃÿÂÿÂÿÃÿ¾ÿ·ÿ·ÿ·ÿ»ÿ¶ÿ¸ÿ»ÿ¿ÿÆÿÊÿÇÿÈÿÅÿÃÿÁÿºÿ°ÿ­ÿªÿ§ÿ¥ÿ¤ÿ¬ÿ°ÿ¶ÿ»ÿÂÿÃÿÇÿÉÿÌÿÌÿÍÿÍÿÏÿÍÿÐÿÍÿÈÿÈÿÈÿÈÿÃÿ½ÿ½ÿ¾ÿ¸ÿ·ÿ·ÿ²ÿ²ÿ¯ÿ²ÿ³ÿ¶ÿ¹ÿ·ÿºÿ¶ÿ°ÿ­ÿ¯ÿ«ÿ¤ÿ¡ÿ£ÿ¤ÿ¡ÿ¤ÿªÿ¯ÿ¯ÿ·ÿ¾ÿÄÿÇÿÊÿÍÿÔÿÔÿÔÿ×ÿÓÿÓÿÒÿÐÿÎÿÏÿÏÿÏÿÎÿÎÿÊÿÍÿÌÿÈÿÉÿÊÿÈÿÆÿÉÿËÿÊÿÏÿÑÿÎÿÉÿÇÿÂÿÀÿ¾ÿ¹ÿ»ÿ¹ÿ¶ÿ¸ÿ½ÿÄÿÈÿÍÿÓÿÙÿßÿçÿèÿêÿëÿêÿïÿëÿçÿåÿßÿÞÿßÿÝÿÜÿÚÿÜÿÚÿÛÿÛÿØÿÓÿÍÿÌÿÌÿÉÿÊÿÏÿÒÿÕÿÙÿÓÿÐÿÍÿÄÿÉÿÇÿÆÿÄÿÇÿÎÿÐÿÒÿÛÿÛÿÚÿàÿåÿçÿïÿõÿùÿûÿüÿûÿøÿúÿýÿûÿúÿüÿüÿùÿúÿûÿûÿøÿøÿ÷ÿ÷ÿ÷ÿôÿîÿèÿæÿàÿÚÿÖÿÑÿÒÿÕÿÚÿáÿåÿéÿìÿðÿõÿûÿýÿþÿûÿùÿøÿòÿòÿðÿöÿûÿýÿþÿøÿðÿëÿéÿæÿæÿàÿÝÿÜÿâÿèÿéÿíÿðÿ÷ÿûÿûÿÿÿ    ûÿôÿíÿëÿèÿåÿàÿßÿáÿäÿêÿïÿðÿõÿøÿúÿþÿ ýÿúÿùÿöÿûÿüÿýÿþÿþÿúÿóÿîÿéÿãÿÜÿÖÿÚÿÚÿÚÿßÿäÿîÿðÿóÿöÿõÿöÿúÿýÿþÿþÿüÿüÿýÿúÿøÿòÿöÿôÿðÿïÿóÿõÿôÿöÿûÿ÷ÿùÿûÿúÿþÿÿÿûÿùÿôÿïÿíÿæÿàÿÞÿÞÿ×ÿÔÿ×ÿÜÿÛÿáÿæÿçÿëÿñÿîÿïÿóÿõÿ÷ÿ÷ÿöÿðÿéÿçÿêÿåÿåÿêÿêÿéÿèÿêÿêÿêÿêÿãÿãÿåÿîÿïÿðÿóÿòÿëÿéÿäÿÚÿÒÿÑÿÌÿÌÿÌÿÏÿÏÿÓÿØÿÛÿÜÿÙÿ×ÿÙÿÞÿâÿåÿëÿîÿðÿñÿðÿíÿèÿçÿåÿäÿãÿáÿåÿèÿæÿçÿëÿíÿîÿòÿöÿ÷ÿõÿôÿòÿóÿîÿìÿâÿßÿÜÿÖÿÑÿÎÿÌÿÏÿÓÿÚÿÞÿáÿèÿéÿèÿêÿìÿéÿéÿéÿëÿçÿèÿæÿäÿâÿàÿÚÿÛÿÛÿàÿÞÿàÿáÿèÿéÿìÿñÿöÿùÿþÿýÿÿÿÿÿúÿóÿðÿëÿëÿçÿåÿßÿÝÿÙÿÛÿßÿäÿèÿéÿëÿíÿîÿíÿóÿôÿ÷ÿùÿûÿøÿøÿöÿöÿõÿøÿöÿùÿ÷ÿõÿöÿöÿýÿÿÿ ùÿ÷ÿöÿùÿøÿúÿ üÿûÿúÿ÷ÿøÿùÿûÿþÿ ! !   %'#!"   %&+.0/.1+'#!$%(,*))(#$ üÿûÿ "%(02666:52.(! #!#%(*(**)" "&)(**-,-1221,('$ !! $%%)))178574--)!  #&).424701.*'!!%).24:>>=::60)  $%)*-//..,,-&  "+-.463//)$  "#$&')-+,,)("$*,31320*$  !#%%$*-.-0/*'""%(,,.232/*'!"%%%$#)++)$#$&"$)*./11-"   !##!  (%!"   þÿÿÿþÿúÿöÿúÿùÿýÿ  ÿÿüÿóÿïÿóÿôÿõÿüÿ   ýÿøÿõÿóÿóÿóÿóÿóÿóÿ÷ÿöÿøÿøÿýÿ ÿÿûÿöÿòÿîÿêÿìÿïÿöÿÿÿ   ÿÿùÿôÿíÿêÿéÿäÿèÿëÿîÿóÿûÿ  öÿóÿîÿêÿìÿíÿîÿõÿùÿûÿÿÿ  ûÿ÷ÿùÿúÿóÿîÿïÿíÿòÿñÿôÿ÷ÿúÿ   ûÿùÿôÿðÿíÿíÿóÿòÿ÷ÿüÿ   ûÿúÿøÿöÿñÿðÿõÿ÷ÿûÿ  ûÿöÿõÿóÿòÿóÿ÷ÿûÿýÿ  ûÿùÿõÿóÿôÿùÿüÿ # !      )-/.21--("(,/0268663/($!#'+10/49:69:70+*+&),,,,0-15767;88821-*&$ !!!$(+,011331012/.('%)+-.479;<==AB@?<40+'#!! ! #%..044776442-*$%(-36:<A@B@853/)""(+154:>><:720+$!!!$%%)+.22597653.'&$ &%(,-.3561.0,' #(*,()'$     øÿôÿðÿîÿîÿíÿîÿíÿñÿ÷ÿýÿþÿüÿøÿöÿóÿîÿíÿëÿëÿðÿñÿïÿõÿ÷ÿúÿüÿþÿüÿûÿôÿîÿíÿéÿãÿàÿÜÿÛÿÛÿÜÿâÿáÿåÿçÿìÿëÿëÿíÿëÿîÿíÿîÿîÿëÿçÿäÿàÿÞÿâÿáÿáÿåÿäÿåÿåÿæÿéÿêÿêÿìÿèÿêÿíÿîÿëÿåÿâÿâÿâÿâÿßÿÞÿÝÿÝÿÚÿÙÿÚÿÚÿÛÿØÿ×ÿÝÿÜÿÚÿÚÿØÿÚÿÖÿÒÿÕÿÕÿÑÿÌÿÇÿÇÿÇÿÅÿÈÿÇÿÆÿÉÿÐÿÑÿÑÿ×ÿÙÿßÿÞÿàÿâÿßÿÞÿÚÿÖÿÐÿÊÿÈÿÂÿÁÿ¿ÿ¾ÿ½ÿ¾ÿÁÿÄÿÄÿÉÿÉÿÉÿÈÿÆÿÆÿÉÿÅÿÄÿÃÿ¿ÿ¼ÿ¿ÿ½ÿ·ÿºÿºÿ»ÿ¾ÿÀÿÁÿÃÿ¿ÿÄÿÆÿÄÿÃÿÄÿÈÿÈÿÈÿÇÿÁÿÂÿÆÿÄÿÀÿ»ÿ½ÿ¾ÿºÿ½ÿÂÿÂÿÄÿÅÿÇÿÇÿÊÿÌÿÇÿÃÿÁÿ¾ÿ»ÿ¶ÿ°ÿ­ÿ®ÿ®ÿªÿ§ÿ¨ÿªÿ­ÿ­ÿ¯ÿ±ÿ°ÿ·ÿ¾ÿ¾ÿ¾ÿÃÿÇÿÇÿÎÿÍÿÉÿÅÿÃÿ¼ÿ»ÿ¹ÿ´ÿ°ÿ³ÿµÿ¹ÿºÿ½ÿÂÿÂÿÄÿÊÿÈÿÇÿÉÿÇÿÄÿÄÿÁÿ¼ÿ¹ÿ»ÿ·ÿ¸ÿµÿ¹ÿ¸ÿ·ÿ»ÿ¼ÿ¼ÿ¿ÿÁÿÁÿÁÿÅÿËÿÎÿÎÿÐÿÓÿÏÿÏÿÎÿÉÿÌÿÈÿÄÿÁÿÂÿ¿ÿ½ÿÀÿÃÿÅÿÆÿÊÿÐÿÐÿÒÿÒÿÎÿÏÿÌÿÉÿÅÿÂÿÀÿ½ÿ¼ÿºÿ¹ÿ¸ÿ¹ÿ½ÿ¿ÿÂÿÂÿÈÿÍÿÔÿ×ÿÚÿÝÿßÿãÿáÿáÿàÿáÿáÿÛÿÕÿÔÿÒÿÐÿÏÿÐÿÏÿÏÿÑÿÔÿÙÿÝÿâÿäÿåÿäÿçÿèÿåÿäÿâÿãÿÝÿßÿÜÿØÿÔÿØÿÕÿÔÿÖÿÚÿÜÿàÿåÿæÿæÿìÿîÿñÿóÿòÿôÿðÿñÿòÿóÿñÿïÿîÿíÿìÿïÿðÿòÿòÿôÿúÿüÿûÿûÿúÿûÿóÿòÿóÿôÿîÿéÿçÿæÿéÿèÿçÿæÿæÿßÿãÿâÿâÿàÿèÿêÿëÿîÿõÿõÿõÿûÿûÿúÿ÷ÿ÷ÿöÿóÿóÿñÿíÿìÿíÿìÿíÿóÿøÿøÿýÿÿÿüÿùÿõÿõÿôÿóÿíÿìÿçÿâÿàÿáÿÝÿÝÿáÿâÿßÿâÿèÿìÿîÿïÿóÿ÷ÿüÿ÷ÿùÿôÿñÿñÿòÿöÿõÿôÿøÿûÿûÿúÿüÿùÿûÿýÿÿÿÿÿÿÿÿÿüÿûÿúÿøÿòÿòÿôÿõÿñÿñÿõÿôÿñÿîÿîÿñÿóÿðÿðÿñÿñÿóÿõÿõÿõÿöÿôÿïÿëÿíÿéÿéÿìÿíÿìÿïÿóÿöÿúÿüÿþÿÿÿüÿþÿùÿúÿöÿòÿñÿíÿëÿíÿëÿèÿêÿíÿìÿîÿîÿîÿïÿóÿôÿôÿõÿøÿùÿöÿúÿøÿúÿöÿûÿõÿöÿôÿöÿòÿñÿïÿóÿ÷ÿùÿûÿûÿýÿüÿÿÿüÿþÿúÿùÿ÷ÿöÿ÷ÿöÿøÿ÷ÿøÿùÿúÿúÿúÿøÿüÿ÷ÿùÿùÿüÿúÿûÿÿÿþÿÿÿÿÿûÿúÿýÿÿÿüÿúÿüÿýÿüÿøÿ÷ÿ÷ÿõÿõÿòÿøÿõÿøÿúÿûÿþÿÿÿÿÿ üÿùÿüÿøÿûÿþÿþÿ   þÿþÿýÿÿÿûÿÿÿþÿþÿÿÿÿÿÿÿÿÿþÿþÿÿÿ  þÿÿÿýÿÿÿýÿùÿúÿýÿýÿÿÿÿÿ  ÿÿþÿùÿùÿõÿõÿøÿ÷ÿúÿúÿ ÿÿüÿýÿýÿûÿýÿþÿýÿúÿÿÿüÿÿÿÿÿÿÿÿÿýÿúÿýÿúÿ÷ÿòÿïÿïÿëÿëÿîÿíÿöÿ÷ÿüÿýÿþÿýÿûÿøÿûÿúÿ÷ÿïÿïÿíÿìÿîÿìÿëÿìÿëÿëÿìÿîÿìÿðÿïÿìÿîÿëÿëÿêÿïÿïÿñÿòÿíÿîÿíÿëÿáÿÝÿÞÿÛÿÙÿÙÿÛÿàÿâÿäÿçÿìÿëÿïÿñÿîÿêÿßÿÜÿÜÿÚÿØÿÖÿÕÿÕÿÙÿØÿØÿÙÿÙÿÙÿ×ÿÛÿÙÿÔÿ×ÿÖÿÓÿÚÿÝÿÞÿßÿàÿßÿÛÿ×ÿÔÿÎÿÈÿËÿÈÿÊÿÆÿÈÿÊÿÎÿÒÿÙÿÙÿÚÿØÿÔÿÑÿÒÿÎÿÇÿÇÿÅÿÁÿÀÿ¹ÿºÿ¶ÿ¹ÿºÿ½ÿ»ÿ»ÿ¾ÿ½ÿ¿ÿÅÿÇÿÊÿÏÿÑÿÐÿÐÿÐÿÒÿÒÿÏÿÎÿÉÿÆÿÆÿÅÿÂÿÀÿ½ÿÀÿÅÿËÿÌÿÎÿÐÿÎÿÊÿÆÿÅÿÄÿÄÿ¾ÿ¼ÿ¾ÿ½ÿ¼ÿ¹ÿºÿ·ÿ¶ÿ½ÿ¾ÿ¼ÿ¼ÿ»ÿ¼ÿ¾ÿ¾ÿ»ÿ¹ÿ¿ÿÁÿÂÿÂÿÁÿÂÿÂÿÅÿÅÿÅÿÁÿÄÿÅÿÇÿÄÿÇÿÉÿÉÿÉÿÍÿÌÿÃÿÅÿÅÿÃÿÀÿ»ÿºÿ¸ÿ´ÿ´ÿ³ÿ°ÿ°ÿ·ÿ½ÿ¿ÿ¿ÿ»ÿÁÿÄÿÆÿÇÿÆÿÅÿÂÿÃÿÄÿÇÿÈÿÄÿÃÿÅÿÁÿ¾ÿ¾ÿ»ÿ¶ÿ¼ÿ¿ÿÆÿÅÿÇÿÌÿÎÿÔÿÕÿÙÿØÿÚÿÔÿÓÿÕÿÎÿÉÿÅÿ¾ÿ¾ÿÂÿÂÿÂÿÂÿÂÿÅÿÆÿÅÿÉÿÍÿÊÿÊÿÐÿÖÿÖÿÒÿÒÿÕÿÕÿÕÿÔÿÑÿÎÿÈÿÆÿÃÿÄÿÆÿÇÿÈÿÊÿÏÿÑÿÓÿÖÿÜÿÞÿÝÿàÿÞÿØÿÖÿÐÿËÿÆÿÈÿÆÿÄÿÆÿÆÿÈÿÇÿÈÿÌÿÌÿËÿÐÿÏÿÍÿÒÿÔÿÕÿÖÿÖÿÖÿÕÿÓÿÔÿÓÿÑÿÎÿÌÿÎÿÎÿÐÿÏÿÐÿÕÿÕÿÙÿÞÿâÿáÿáÿßÿÝÿÞÿÚÿÕÿÕÿÓÿÑÿÏÿÏÿÐÿÐÿÌÿÎÿÐÿÒÿÔÿØÿØÿÚÿÚÿÞÿßÿâÿàÿãÿàÿÝÿÝÿßÿßÿÜÿÝÿØÿØÿÙÿ×ÿÓÿÕÿÖÿÚÿßÿäÿéÿëÿîÿôÿðÿìÿçÿäÿàÿÛÿÕÿÐÿÍÿÍÿËÿÈÿÇÿÍÿÎÿÐÿÐÿÑÿÍÿÑÿÓÿÙÿÙÿÛÿÚÿÚÿÜÿÜÿÛÿÞÿÝÿÙÿ×ÿÔÿÔÿØÿÓÿÐÿÒÿÔÿÖÿÙÿÜÿßÿáÿêÿìÿéÿíÿêÿéÿãÿàÿÞÿÝÿÚÿÜÿÝÿÞÿáÿäÿãÿçÿìÿìÿëÿðÿôÿ÷ÿøÿ÷ÿüÿýÿÿÿÿÿýÿüÿýÿûÿùÿöÿôÿòÿñÿôÿóÿ÷ÿõÿ÷ÿøÿúÿþÿùÿùÿøÿøÿñÿêÿéÿéÿéÿéÿëÿêÿëÿîÿðÿðÿñÿîÿìÿîÿîÿíÿíÿïÿïÿïÿïÿõÿòÿñÿñÿðÿíÿëÿçÿæÿãÿàÿâÿßÿãÿæÿëÿîÿñÿòÿôÿõÿõÿñÿðÿëÿìÿçÿåÿâÿçÿëÿêÿíÿðÿïÿîÿôÿ÷ÿõÿøÿüÿýÿûÿúÿþÿýÿýÿÿÿÿÿþÿþÿ ýÿ÷ÿõÿòÿñÿëÿæÿçÿåÿæÿéÿéÿéÿìÿìÿðÿñÿðÿòÿóÿ÷ÿþÿøÿöÿóÿñÿôÿòÿòÿñÿìÿìÿìÿéÿèÿêÿîÿðÿðÿõÿùÿþÿþÿýÿÿÿýÿúÿöÿôÿñÿïÿðÿëÿëÿîÿðÿðÿðÿñÿòÿïÿòÿòÿôÿõÿöÿöÿõÿ÷ÿüÿþÿûÿýÿüÿþÿ  þÿüÿýÿüÿúÿýÿýÿýÿ ÿÿÿÿöÿöÿýÿýÿ " !    "$&"%$!($%(+*'   #&)0-02142/,$##%$"!!%%"(,,378968500,,'%)()-/2-01599;8610021///1.*+.-323265678:==;;97876:=?DHLMQPOPKHEAACDA97779677::=>?ACBC?=?=9875211111/5:?AA;;=97754430///1-.*(+/-/11344-+,+%&$# $"&&*.023511-,*+&'&&**')$$'$"!%'('&##!"#"! "%&**-/,-10-+*)&&(('$&())+,++/011595552..-*)*+/178;763::7210.*)($! #&*,124103:89643/-,)'$""').38;=@=>>;893/112/0/13633459<<=AFEGEFDACC@?===@?CFEEJJHHE>:744354262347788;>@@EIJJGGED@?>;=?=BKLPPQRQQNICA?<>=8==?ACEFGFGNPOMNPRTRQLMIKGFFHLMJQRSSVUQKI@=@:8745323458597679<<9<?9876332579;=DFNRRVSPNMJGEBB@?=;><<769599<=BC@CHGFB@=>>?975;9==@A<;:73/.--+*&*,,+-*+)'&'%#$ %! $(.010-'#  "!         ÿÿûÿÿÿ       ")++-+'#"  !!!  #**&''$$ &(#$&"" $#!# !      þÿûÿûÿþÿûÿõÿøÿúÿúÿùÿ÷ÿûÿüÿûÿúÿùÿõÿöÿûÿüÿùÿøÿúÿøÿ÷ÿõÿôÿñÿïÿîÿîÿëÿèÿåÿéÿëÿëÿïÿôÿñÿñÿôÿôÿðÿêÿåÿäÿáÿàÿÜÿÝÿÞÿÛÿÝÿÝÿÞÿÝÿáÿÝÿÜÿÜÿÜÿÚÿØÿ×ÿÙÿ×ÿÕÿÚÿÙÿÛÿÛÿÜÿ×ÿÖÿÙÿÖÿ×ÿÕÿÓÿÓÿÎÿÑÿÒÿÏÿÎÿÏÿÌÿÊÿÅÿÆÿÀÿÃÿ½ÿºÿ¹ÿ»ÿ»ÿ»ÿ½ÿÂÿÀÿÅÿÆÿÄÿÃÿÃÿÀÿ»ÿ»ÿ»ÿºÿ½ÿºÿ·ÿ³ÿ¶ÿ´ÿµÿ³ÿ±ÿ²ÿ²ÿ³ÿµÿµÿ¶ÿ¾ÿÀÿÅÿÈÿÈÿÈÿÇÿÅÿÁÿ¾ÿ»ÿ¶ÿ´ÿ¯ÿ­ÿ©ÿ¨ÿ©ÿªÿ¬ÿªÿ¯ÿ«ÿ¬ÿ¯ÿ³ÿ²ÿ¶ÿ³ÿ³ÿ³ÿ°ÿ²ÿ³ÿ°ÿ¯ÿ­ÿ¬ÿ¬ÿ¦ÿ¥ÿ£ÿ¢ÿ£ÿ£ÿ¡ÿ¡ÿ£ÿ£ÿ§ÿªÿ®ÿªÿ©ÿ¦ÿ¤ÿ¤ÿ¢ÿœÿ”ÿ‘ÿ•ÿ’ÿÿ‘ÿ‘ÿÿ’ÿ”ÿ™ÿÿœÿžÿÿŸÿ¢ÿ ÿÿœÿœÿ˜ÿ“ÿ—ÿ•ÿ”ÿ–ÿ“ÿÿ”ÿ”ÿÿÿ‘ÿ”ÿ•ÿšÿœÿÿ ÿ¢ÿ£ÿ ÿœÿ—ÿÿÿ‡ÿˆÿ†ÿ‚ÿƒÿÿ‚ÿ„ÿ…ÿ„ÿ„ÿ‰ÿŒÿŒÿŽÿÿ‘ÿÿ‘ÿÿÿ‘ÿ‘ÿÿŒÿ‰ÿ†ÿÿ‚ÿ€ÿÿ~ÿ}ÿ~ÿ€ÿ„ÿ†ÿ‰ÿ‡ÿŠÿŠÿ‰ÿ…ÿ‚ÿÿ~ÿ~ÿ{ÿyÿyÿzÿ|ÿ}ÿ|ÿ|ÿÿ|ÿ‚ÿ…ÿÿ‚ÿƒÿ€ÿ‚ÿ‚ÿƒÿÿ‚ÿ‚ÿƒÿ„ÿ‡ÿ†ÿ†ÿ…ÿƒÿ‚ÿƒÿƒÿ‚ÿƒÿ…ÿ†ÿ‰ÿŒÿ‹ÿŒÿŽÿÿÿŽÿÿˆÿ€ÿÿ}ÿyÿwÿvÿqÿrÿsÿyÿyÿ}ÿ€ÿ†ÿ†ÿˆÿ†ÿ…ÿƒÿ„ÿ†ÿˆÿ†ÿ„ÿÿÿÿ{ÿwÿwÿsÿqÿsÿrÿvÿzÿ~ÿÿ€ÿÿƒÿ„ÿƒÿ„ÿ†ÿ„ÿ…ÿÿ€ÿ~ÿÿ}ÿÿ{ÿ|ÿÿ„ÿ…ÿ„ÿ†ÿ‚ÿ…ÿ‰ÿˆÿ‡ÿ‡ÿ†ÿ‡ÿˆÿ…ÿƒÿ‚ÿ„ÿ}ÿ{ÿÿ€ÿ|ÿ~ÿ}ÿ}ÿ‚ÿ„ÿƒÿ‰ÿ‹ÿ‹ÿŽÿ’ÿ“ÿ“ÿ’ÿÿ‘ÿ‘ÿŠÿ‰ÿŽÿÿÿÿÿ•ÿ”ÿ˜ÿ—ÿ˜ÿ–ÿ”ÿ–ÿ™ÿ•ÿ—ÿ™ÿ›ÿšÿ•ÿ’ÿŽÿÿ”ÿ”ÿ“ÿÿÿ‘ÿ‘ÿ”ÿ•ÿ–ÿ–ÿ˜ÿšÿ›ÿšÿœÿ ÿ¢ÿ¢ÿÿ›ÿšÿ”ÿ–ÿ™ÿ›ÿŸÿ ÿžÿ¡ÿ ÿ¤ÿ¦ÿ«ÿ©ÿ­ÿ®ÿ°ÿ¯ÿ±ÿ«ÿªÿ¬ÿªÿªÿ¨ÿ¦ÿ¨ÿ£ÿ£ÿ¥ÿ¢ÿ¢ÿŸÿ£ÿ©ÿ«ÿ­ÿ°ÿ²ÿ´ÿ±ÿ¯ÿ¯ÿ°ÿ²ÿ­ÿ§ÿ§ÿ¨ÿ§ÿ¬ÿ¬ÿ²ÿ´ÿ´ÿ¹ÿºÿ½ÿ¿ÿÃÿÀÿ¿ÿÃÿ¿ÿÀÿÂÿÂÿÃÿÁÿÀÿ¾ÿ¼ÿºÿ¼ÿ¼ÿ¼ÿ½ÿºÿ¸ÿ»ÿ¾ÿÀÿÁÿÄÿÇÿÌÿÉÿÉÿÊÿËÿÉÿÇÿÃÿÄÿÂÿÃÿÅÿÇÿÃÿÆÿÇÿÉÿÎÿÓÿÓÿÖÿÙÿÛÿÝÿÞÿÞÿàÿÝÿÜÿØÿÕÿÒÿÓÿÔÿÕÿÖÿ×ÿÙÿ×ÿ×ÿØÿÙÿÜÿàÿáÿßÿÜÿßÿßÿÝÿÝÿÜÿÞÿÛÿÝÿÜÿÛÿÚÿØÿÙÿÙÿÛÿÛÿàÿßÿáÿäÿâÿæÿäÿäÿçÿâÿåÿæÿæÿåÿæÿåÿáÿàÿàÿßÿÞÿßÿâÿÞÿÞÿàÿäÿèÿêÿéÿêÿîÿîÿòÿóÿôÿôÿòÿíÿëÿðÿïÿîÿïÿïÿòÿôÿ÷ÿ÷ÿüÿýÿýÿûÿøÿôÿ÷ÿùÿòÿñÿïÿïÿïÿñÿðÿòÿðÿòÿñÿôÿöÿõÿ÷ÿøÿøÿ÷ÿùÿõÿñÿïÿòÿôÿôÿúÿóÿôÿúÿþÿøÿÿÿþÿÿÿþÿùÿøÿõÿöÿõÿòÿíÿíÿëÿìÿíÿîÿòÿòÿòÿôÿöÿ÷ÿöÿòÿíÿñÿñÿíÿìÿéÿèÿæÿäÿæÿçÿèÿèÿëÿîÿñÿðÿôÿûÿÿÿÿÿûÿûÿüÿøÿóÿòÿîÿéÿæÿãÿæÿçÿçÿãÿãÿåÿåÿäÿäÿçÿæÿëÿëÿéÿèÿéÿéÿåÿâÿÞÿÜÿÞÿÞÿÜÿàÿßÿàÿáÿåÿèÿèÿçÿëÿðÿñÿïÿìÿìÿìÿìÿëÿìÿêÿëÿèÿæÿäÿåÿèÿæÿçÿåÿåÿåÿéÿêÿíÿêÿëÿìÿíÿìÿêÿéÿåÿâÿáÿßÿÙÿÜÿÚÿÚÿØÿØÿÚÿÜÿÛÿâÿèÿêÿëÿîÿîÿòÿòÿíÿîÿìÿæÿçÿäÿáÿàÿâÿäÿéÿëÿëÿéÿìÿïÿïÿðÿîÿìÿëÿíÿëÿëÿéÿêÿæÿçÿäÿãÿßÿãÿâÿâÿâÿçÿéÿæÿæÿîÿðÿíÿïÿíÿìÿïÿéÿèÿæÿãÿåÿæÿäÿäÿãÿåÿäÿåÿäÿâÿèÿìÿìÿíÿïÿðÿôÿòÿóÿòÿîÿìÿçÿêÿèÿìÿíÿèÿåÿåÿäÿåÿèÿíÿìÿíÿíÿïÿñÿñÿïÿðÿðÿðÿîÿëÿèÿçÿçÿèÿæÿèÿáÿãÿáÿãÿäÿåÿæÿèÿêÿîÿðÿóÿøÿöÿõÿòÿñÿðÿñÿòÿïÿðÿðÿðÿðÿñÿìÿìÿîÿðÿõÿõÿ÷ÿõÿñÿôÿñÿîÿíÿíÿìÿëÿéÿçÿåÿæÿäÿâÿÞÿßÿßÿáÿãÿåÿâÿæÿêÿñÿòÿòÿóÿõÿôÿóÿðÿóÿòÿõÿòÿòÿñÿòÿñÿõÿøÿùÿýÿþÿýÿÿÿþÿþÿýÿúÿûÿøÿóÿðÿðÿïÿðÿòÿñÿôÿñÿíÿðÿëÿêÿêÿéÿèÿìÿíÿïÿñÿóÿñÿóÿöÿøÿùÿøÿúÿøÿøÿûÿøÿøÿûÿýÿýÿÿÿüÿöÿôÿõÿòÿóÿòÿðÿïÿîÿíÿïÿñÿíÿñÿóÿôÿõÿ÷ÿöÿøÿöÿöÿöÿöÿõÿôÿöÿøÿ÷ÿ÷ÿúÿüÿûÿûÿýÿûÿõÿüÿýÿ ýÿýÿûÿùÿûÿùÿôÿòÿïÿòÿóÿïÿðÿîÿîÿëÿìÿïÿðÿõÿùÿøÿùÿøÿõÿ÷ÿøÿøÿ÷ÿöÿ÷ÿ÷ÿóÿöÿ÷ÿøÿúÿüÿÿÿüÿúÿøÿøÿõÿõÿøÿùÿöÿóÿ÷ÿõÿ÷ÿúÿùÿúÿüÿúÿþÿüÿûÿüÿüÿþÿÿÿ  þÿúÿøÿúÿøÿøÿúÿúÿøÿùÿýÿúÿýÿþÿ      "#+.//25430+(*%# ##(! $$"'').10263/.-("! ! $#!%),)+(&'&"$   þÿüÿûÿþÿ   üÿúÿøÿóÿöÿõÿóÿôÿôÿõÿõÿöÿûÿþÿÿÿ  ÿÿýÿùÿ÷ÿõÿñÿôÿòÿñÿñÿëÿëÿìÿêÿéÿéÿêÿêÿëÿìÿêÿéÿíÿíÿíÿêÿîÿîÿðÿîÿòÿôÿòÿóÿôÿùÿùÿûÿüÿýÿüÿúÿöÿñÿñÿôÿïÿðÿíÿèÿäÿæÿæÿäÿãÿâÿâÿãÿßÿßÿâÿÞÿÞÿÝÿÚÿÝÿßÿßÿÞÿÜÿÚÿÞÿÞÿàÿßÿàÿáÿâÿãÿåÿæÿçÿêÿêÿéÿéÿèÿèÿéÿìÿéÿèÿæÿâÿàÿßÿÝÿÚÿØÿ×ÿØÿØÿÙÿØÿØÿ×ÿÙÿÚÿÙÿÙÿ×ÿÙÿÙÿ×ÿÖÿÕÿÔÿÔÿÕÿÕÿÕÿÖÿÕÿÒÿÕÿØÿÙÿÝÿáÿãÿçÿçÿåÿæÿèÿéÿêÿæÿæÿãÿáÿáÿÜÿÙÿÙÿÚÿÙÿÛÿÙÿÚÿÛÿÚÿÙÿÛÿÛÿÚÿÛÿÞÿÝÿßÿÜÿÜÿÜÿÞÿÖÿÙÿÚÿÛÿÚÿÙÿÙÿÛÿÚÿàÿáÿãÿßÿäÿßÿÝÿÛÿáÿâÿàÿßÿÜÿÜÿÙÿÕÿÑÿÑÿÒÿÎÿÎÿÍÿÊÿÈÿÇÿÇÿÌÿÑÿÑÿÏÿÔÿÕÿÐÿÏÿÕÿ×ÿÔÿÓÿÒÿÑÿÏÿÍÿÍÿÑÿÎÿÐÿÓÿÙÿàÿßÿãÿáÿàÿÚÿÜÿÙÿÖÿÕÿÒÿÍÿÌÿÌÿÏÿÊÿÈÿÅÿÅÿÆÿÇÿÄÿÄÿÈÿÇÿÅÿÆÿÌÿËÿÌÿÎÿÍÿÎÿÏÿÒÿÏÿÌÿÍÿÎÿÌÿÈÿÇÿÅÿÊÿÊÿËÿÐÿÓÿÓÿÕÿÖÿÛÿÛÿÜÿÜÿÜÿÝÿÝÿÙÿÓÿÓÿÒÿËÿÊÿÊÿÊÿÇÿÇÿÅÿÈÿÅÿÃÿÈÿÈÿÉÿÍÿÓÿÔÿÓÿ×ÿ×ÿØÿÛÿÚÿ×ÿÙÿ×ÿÔÿÒÿÖÿ×ÿÔÿ×ÿÚÿÜÿâÿâÿâÿäÿåÿâÿäÿæÿçÿäÿáÿâÿàÿÜÿÛÿÚÿÚÿÜÿÜÿÙÿÖÿØÿÙÿÙÿÙÿÜÿÞÿßÿÛÿÚÿ×ÿÚÿÚÿàÿÝÿÞÿâÿâÿãÿåÿãÿãÿèÿíÿñÿñÿðÿðÿôÿòÿðÿðÿñÿïÿìÿñÿôÿîÿïÿìÿêÿëÿìÿêÿêÿêÿíÿëÿëÿíÿïÿõÿòÿòÿóÿöÿôÿõÿúÿøÿ÷ÿûÿùÿõÿóÿõÿöÿúÿûÿøÿ÷ÿùÿøÿüÿþÿýÿúÿûÿøÿ÷ÿòÿôÿôÿñÿñÿóÿõÿúÿûÿþÿþÿÿÿÿÿ  þÿýÿýÿúÿøÿ÷ÿõÿöÿñÿðÿòÿõÿõÿõÿ÷ÿüÿûÿÿÿþÿÿÿ  ÿÿõÿöÿôÿòÿòÿñÿðÿòÿôÿöÿòÿõÿõÿøÿøÿøÿùÿùÿýÿÿÿýÿÿÿýÿüÿýÿÿÿ  þÿýÿ÷ÿóÿðÿðÿðÿéÿèÿæÿéÿêÿìÿèÿëÿêÿëÿïÿðÿôÿõÿ÷ÿöÿøÿ÷ÿûÿøÿøÿ÷ÿúÿ÷ÿòÿõÿøÿøÿùÿÿÿýÿüÿúÿõÿðÿïÿëÿêÿèÿåÿãÿâÿåÿæÿçÿèÿìÿêÿëÿîÿóÿïÿóÿóÿïÿñÿóÿïÿïÿïÿñÿôÿðÿðÿõÿõÿöÿ÷ÿúÿøÿ÷ÿúÿþÿýÿúÿúÿÿÿûÿùÿûÿ÷ÿðÿëÿæÿçÿáÿãÿäÿãÿâÿáÿãÿáÿâÿäÿèÿëÿèÿèÿçÿéÿëÿîÿôÿíÿïÿíÿéÿéÿíÿêÿìÿîÿíÿîÿîÿêÿêÿëÿëÿìÿîÿïÿìÿéÿéÿçÿäÿâÿàÿßÿÛÿÕÿÖÿÖÿÓÿÖÿÚÿÙÿÙÿÚÿÝÿÞÿßÿâÿãÿçÿçÿéÿæÿåÿæÿçÿéÿìÿèÿèÿïÿîÿîÿîÿóÿôÿ÷ÿ÷ÿòÿòÿóÿõÿôÿïÿîÿêÿçÿãÿæÿãÿãÿâÿçÿèÿçÿçÿêÿéÿëÿîÿðÿñÿïÿòÿòÿóÿôÿöÿ÷ÿòÿôÿõÿòÿöÿòÿñÿöÿûÿüÿÿÿÿÿÿÿÿÿûÿ÷ÿöÿñÿòÿñÿóÿîÿìÿïÿòÿðÿðÿôÿ÷ÿõÿ÷ÿúÿûÿüÿþÿþÿÿÿþÿþÿþÿÿÿÿÿþÿ    ##!('(*+-./0/1-../,')*)&)$%&*)*),-./125420++00-/257;>?=?:;=@=<8676342331-13487:8<@BCDCBB?<<@>:<=<??@DBCFFIJLJECDFG@<7646::<;>CBCCDJLKLGLLKHGHHJHIHHEHFFKFA@?=>>>;<:;;<><989==;@?BDCDGDFGIJFGFHHEHGEBAA>=@:9;885411/03/,(+--.0/4013.1202326543553474420,,,+*,&&%#""! # !#! # " # !     ÿÿÿÿüÿùÿ÷ÿúÿ÷ÿ÷ÿøÿöÿøÿùÿúÿúÿúÿúÿûÿùÿùÿ÷ÿùÿ÷ÿùÿùÿùÿúÿúÿûÿüÿþÿúÿùÿúÿøÿ÷ÿõÿøÿ÷ÿ÷ÿôÿóÿôÿðÿñÿïÿîÿëÿèÿåÿãÿäÿåÿåÿäÿåÿåÿæÿèÿèÿêÿíÿîÿîÿîÿìÿêÿìÿêÿêÿêÿéÿéÿëÿêÿìÿíÿêÿêÿìÿîÿìÿèÿêÿëÿèÿêÿéÿêÿçÿçÿäÿÞÿÚÿÔÿÕÿ×ÿÒÿÑÿÑÿÎÿÏÿÏÿÓÿÔÿ×ÿÕÿÕÿÙÿÛÿ×ÿÙÿÖÿÔÿÖÿÖÿÔÿÒÿÓÿÓÿÓÿÕÿÕÿÖÿ×ÿÙÿÖÿÕÿÔÿÙÿÚÿØÿÙÿÖÿÕÿÔÿÒÿÓÿÐÿÇÿÆÿÆÿÃÿ¿ÿ½ÿ¾ÿºÿ¹ÿ·ÿ¸ÿ¸ÿ¶ÿ¶ÿ¹ÿ»ÿµÿºÿ¾ÿ½ÿÁÿ¿ÿÃÿÁÿ¼ÿ¼ÿ»ÿ¼ÿÁÿ¾ÿ¾ÿ¿ÿÁÿÅÿÅÿÅÿÂÿÁÿÀÿÀÿ½ÿ½ÿÁÿÂÿÀÿ¿ÿ»ÿ¹ÿºÿ¶ÿ¯ÿ®ÿªÿ«ÿ©ÿ¬ÿ©ÿ¨ÿ«ÿ­ÿ­ÿ­ÿªÿ­ÿ¬ÿ¬ÿ¬ÿ­ÿ°ÿ°ÿ­ÿ®ÿ¬ÿ¬ÿªÿ«ÿ«ÿ¯ÿ²ÿ¶ÿ³ÿµÿ¹ÿ½ÿ¼ÿ¹ÿºÿ»ÿ¼ÿ¶ÿ³ÿ­ÿ¯ÿ¬ÿ§ÿ©ÿ¤ÿ£ÿ ÿŸÿ¡ÿ¥ÿ¤ÿ¥ÿ¢ÿ¥ÿ¤ÿ¥ÿ¦ÿ¦ÿ§ÿ§ÿ«ÿ©ÿ§ÿ©ÿªÿ¨ÿ¨ÿ¥ÿ£ÿ¤ÿ¨ÿ¨ÿªÿ¨ÿ«ÿ¬ÿ­ÿ®ÿ³ÿ´ÿ¹ÿ»ÿºÿ¸ÿ¹ÿ¹ÿ¸ÿ³ÿ³ÿ³ÿ²ÿ°ÿ°ÿªÿ©ÿªÿ­ÿ­ÿ®ÿ¬ÿ¯ÿ´ÿ±ÿ²ÿ°ÿµÿ·ÿµÿ·ÿµÿ´ÿ³ÿ´ÿ´ÿ´ÿ²ÿ´ÿ²ÿ¸ÿ·ÿµÿ»ÿ¹ÿ½ÿ½ÿ»ÿ½ÿ¾ÿ¼ÿ¾ÿ¿ÿ¿ÿ¾ÿ¹ÿ¹ÿ³ÿ³ÿ¯ÿ®ÿ²ÿ°ÿ¬ÿ«ÿ¬ÿ®ÿ±ÿ³ÿ¶ÿ´ÿ¶ÿ»ÿ·ÿ½ÿ¾ÿ¹ÿ½ÿ¼ÿ¿ÿ»ÿ¼ÿ»ÿ¹ÿ¹ÿ½ÿ»ÿ¼ÿ½ÿ¿ÿ¿ÿÀÿ¿ÿ¿ÿ¾ÿÂÿÀÿÁÿÃÿÃÿÂÿ½ÿ»ÿ½ÿ¾ÿ¹ÿ¹ÿ¸ÿ¹ÿ·ÿ·ÿ³ÿ´ÿ´ÿ¹ÿ¸ÿ·ÿ¶ÿºÿºÿ¸ÿ·ÿ¹ÿ¹ÿ»ÿ·ÿ¹ÿ·ÿºÿ½ÿ¾ÿ¿ÿÂÿÅÿÈÿÇÿÈÿÆÿÉÿËÿÍÿÊÿÉÿÈÿÈÿËÿÈÿÅÿÃÿÁÿÂÿºÿ½ÿºÿºÿ»ÿ¸ÿ¹ÿºÿ¹ÿ»ÿÀÿÀÿÄÿÅÿÅÿÂÿÃÿÃÿÄÿÂÿÄÿÄÿÅÿÃÿÃÿÁÿ¾ÿÁÿÈÿÉÿÈÿÉÿÉÿÉÿÍÿÏÿÑÿÔÿÔÿÑÿÏÿÎÿÍÿÌÿÅÿÃÿÅÿÂÿ¿ÿ»ÿ¾ÿºÿ¹ÿ¹ÿ»ÿ½ÿ¼ÿÁÿÄÿÃÿ¿ÿÂÿÄÿÁÿ¾ÿ¿ÿ½ÿ¿ÿ¿ÿÀÿ½ÿ¾ÿ¿ÿÂÿÁÿÃÿÂÿÃÿÆÿÉÿÇÿÍÿÒÿÔÿÓÿÑÿ×ÿØÿÕÿÔÿÓÿÓÿÍÿÈÿÈÿÉÿÈÿÆÿÄÿÃÿÆÿÉÿÊÿÊÿÉÿËÿÎÿÔÿÔÿÒÿÐÿÎÿÐÿÑÿÑÿÏÿÍÿÊÿÎÿÒÿÏÿÓÿÔÿÔÿÓÿ×ÿØÿÙÿÙÿßÿÚÿÝÿßÿàÿßÿÝÿÞÿÞÿÛÿÚÿ×ÿÑÿÏÿÐÿÎÿÒÿÏÿÓÿÏÿÕÿÖÿÙÿÙÿÙÿØÿ×ÿÙÿØÿØÿØÿ×ÿÔÿÕÿÔÿÑÿÑÿÑÿÓÿ×ÿÖÿÙÿÜÿÞÿÞÿÞÿÞÿáÿßÿàÿçÿèÿæÿèÿâÿåÿãÿÝÿÛÿÚÿÕÿÑÿÎÿÏÿÒÿÔÿØÿÝÿÛÿÝÿßÿàÿÝÿÞÿßÿàÿßÿÝÿÛÿÜÿØÿØÿÙÿ×ÿÕÿÕÿÒÿØÿÝÿÛÿÛÿáÿáÿáÿæÿãÿåÿëÿêÿçÿèÿåÿæÿåÿæÿåÿáÿÞÿßÿßÿàÿßÿßÿßÿáÿãÿãÿâÿåÿäÿäÿåÿèÿçÿçÿçÿèÿêÿìÿæÿäÿéÿëÿèÿèÿéÿíÿíÿðÿóÿõÿöÿùÿùÿøÿùÿ÷ÿôÿöÿôÿðÿðÿðÿíÿëÿåÿçÿçÿêÿìÿëÿíÿîÿîÿðÿñÿóÿñÿòÿóÿñÿóÿôÿõÿôÿñÿóÿôÿóÿòÿòÿôÿõÿöÿýÿûÿûÿûÿÿÿýÿûÿúÿ÷ÿöÿôÿóÿöÿöÿõÿ÷ÿ÷ÿöÿùÿùÿ÷ÿôÿúÿúÿøÿôÿöÿóÿõÿñÿñÿíÿêÿïÿðÿïÿóÿôÿòÿõÿóÿôÿõÿøÿõÿùÿùÿ÷ÿùÿùÿøÿ÷ÿúÿúÿøÿòÿòÿôÿóÿ÷ÿùÿøÿûÿýÿüÿýÿþÿüÿøÿùÿøÿõÿôÿñÿîÿíÿðÿôÿóÿôÿôÿôÿùÿøÿøÿùÿ÷ÿóÿ÷ÿùÿøÿúÿúÿ÷ÿôÿðÿñÿñÿîÿìÿìÿêÿçÿìÿïÿòÿóÿðÿðÿøÿúÿûÿÿÿýÿùÿúÿûÿûÿûÿüÿøÿõÿ÷ÿóÿôÿöÿúÿýÿúÿúÿùÿúÿøÿýÿÿÿÿÿýÿýÿüÿüÿùÿúÿùÿùÿöÿòÿòÿôÿôÿôÿöÿüÿüÿýÿÿÿÿÿýÿÿÿýÿÿÿ   úÿõÿöÿòÿðÿóÿóÿóÿôÿøÿþÿÿÿ    ûÿùÿùÿøÿùÿýÿýÿÿÿÿÿÿÿÿÿÿÿ    ÿÿþÿúÿ÷ÿôÿôÿôÿóÿõÿøÿýÿÿÿ   ÿÿýÿþÿüÿþÿþÿÿÿ        !#"   !" &&)+/111585533//*((('$!! $(&$%$#!"##" "$&'&++).-//015249:42132,)**)*./03133113/01.--,(+--.3799A@ABEEFDHJFBB??<9;<>?CDFEIKKLLGEA><<988<=?BDEFJMRRUVVVXWYZVSQNKJIIJPRVZZ[X\`\[[XWSOOPRRTWXZZ]`ffghhmnrpmpoolhkjhjlqwxvxy|}}z|{}xwussrstvvvw|yxxxxx|||}zwzrrnmmrvwuy{ƒ†……‚…„‚}|zxzyzyx|}~ƒ…ƒ‚ƒ‚…‚‡†…„|ytrsqssvx€†‚‚€‚zxxvtux|{|zxyxx{zxzxxvrnnpmiljhiiknmnooovsqqrstrmljijklpprusruttwuvvxtliecba_b]]addedbdhfbbaa^_WWWW\]][[\]`_^\_\[YWSQRPMMMKLLLKMSUTTTPTQMKLJIDBBAEDDBEDEFIFFEEGD@@@;9<9678877;<:>@===;<9651466468:<:<=9;@@>;984551-*%""  !"%(+*,-+-)%# $&&')+),,*%%%! "  ÿÿþÿþÿýÿýÿýÿúÿþÿ  ûÿùÿùÿûÿùÿùÿ÷ÿöÿúÿûÿüÿýÿùÿúÿóÿñÿòÿîÿïÿðÿïÿñÿòÿóÿõÿôÿôÿùÿúÿúÿüÿúÿúÿÿÿÿÿÿÿýÿúÿùÿ÷ÿñÿïÿïÿîÿèÿæÿçÿéÿêÿëÿìÿíÿíÿìÿéÿêÿëÿìÿíÿéÿèÿèÿèÿåÿäÿãÿæÿæÿçÿéÿëÿêÿëÿîÿîÿòÿóÿîÿîÿôÿöÿõÿöÿ÷ÿøÿõÿòÿïÿëÿèÿæÿâÿáÿâÿéÿèÿèÿêÿæÿèÿçÿéÿéÿåÿåÿâÿâÿáÿàÿÞÿÝÿÝÿßÿàÿãÿæÿçÿèÿéÿéÿëÿîÿîÿîÿíÿíÿñÿîÿíÿëÿîÿïÿðÿðÿêÿèÿçÿèÿëÿéÿæÿêÿíÿëÿîÿîÿïÿëÿéÿëÿëÿèÿëÿèÿãÿàÿáÿáÿáÿáÿàÿßÿàÿâÿäÿèÿêÿëÿëÿîÿñÿôÿúÿõÿóÿðÿïÿñÿòÿîÿìÿìÿéÿìÿìÿëÿïÿòÿõÿôÿõÿõÿôÿôÿõÿóÿòÿñÿðÿíÿðÿîÿëÿéÿéÿîÿíÿìÿñÿðÿòÿôÿóÿóÿõÿúÿúÿ÷ÿ÷ÿøÿùÿúÿûÿøÿúÿøÿøÿøÿðÿïÿíÿîÿïÿïÿñÿôÿòÿôÿõÿôÿòÿõÿòÿóÿðÿîÿéÿæÿæÿåÿçÿæÿçÿèÿæÿæÿçÿëÿêÿéÿèÿæÿçÿéÿçÿéÿèÿëÿìÿëÿíÿéÿèÿãÿãÿáÿáÿâÿåÿæÿæÿèÿëÿëÿëÿéÿêÿíÿïÿêÿèÿçÿåÿãÿÞÿÞÿÞÿßÿÝÿÞÿÝÿÝÿÙÿÙÿ×ÿÜÿÛÿÜÿÞÿÜÿáÿäÿãÿàÿãÿáÿßÿàÿÜÿÜÿÛÿÕÿØÿ×ÿÛÿÚÿØÿÙÿÞÿÜÿÞÿßÿÞÿÞÿÞÿßÿÞÿÛÿÚÿÕÿÖÿÖÿÒÿÐÿÍÿÑÿÐÿÏÿÕÿÙÿ×ÿÙÿÜÿÛÿÛÿÝÿÜÿØÿÙÿÚÿÛÿÕÿÔÿÕÿÕÿÎÿÏÿÐÿÏÿÏÿÑÿÔÿÕÿÕÿÒÿÙÿÚÿÝÿßÿÝÿÞÿÞÿÜÿÛÿÙÿÙÿÖÿÖÿ×ÿ×ÿÔÿÓÿÕÿ×ÿÓÿÔÿ×ÿÕÿÚÿÞÿÝÿÙÿÚÿÛÿâÿáÿçÿäÿæÿçÿåÿáÿãÿÝÿÚÿÚÿÛÿÔÿØÿÞÿàÿâÿâÿåÿæÿèÿçÿîÿëÿêÿêÿêÿëÿîÿêÿëÿìÿìÿíÿéÿëÿëÿìÿëÿéÿêÿìÿêÿìÿìÿíÿíÿíÿìÿìÿëÿïÿïÿëÿèÿâÿáÿãÿáÿâÿãÿåÿéÿëÿíÿíÿìÿîÿñÿîÿîÿðÿíÿïÿðÿïÿïÿëÿèÿçÿêÿëÿíÿíÿîÿðÿóÿôÿòÿòÿôÿõÿøÿùÿõÿ÷ÿ÷ÿöÿõÿôÿñÿóÿðÿðÿòÿñÿòÿñÿòÿôÿ÷ÿ÷ÿõÿ÷ÿ÷ÿöÿöÿôÿöÿöÿùÿ÷ÿ÷ÿõÿ÷ÿùÿùÿõÿöÿøÿøÿûÿýÿþÿüÿÿÿþÿüÿüÿÿÿüÿÿÿýÿúÿ÷ÿ÷ÿöÿóÿõÿ÷ÿõÿõÿõÿøÿõÿöÿöÿùÿûÿúÿúÿüÿüÿûÿøÿ÷ÿôÿôÿõÿôÿ÷ÿúÿûÿùÿøÿþÿûÿýÿÿÿþÿúÿõÿôÿöÿùÿ÷ÿôÿõÿøÿúÿùÿúÿúÿÿÿýÿúÿ÷ÿúÿúÿøÿùÿúÿùÿ÷ÿøÿöÿøÿùÿøÿúÿúÿøÿøÿþÿúÿúÿùÿüÿþÿÿÿþÿúÿøÿõÿöÿóÿíÿïÿïÿñÿíÿïÿòÿóÿòÿõÿóÿòÿñÿïÿëÿéÿéÿèÿæÿåÿæÿçÿìÿëÿêÿêÿëÿðÿîÿíÿíÿîÿîÿíÿëÿïÿïÿíÿìÿìÿìÿêÿèÿèÿçÿãÿßÿßÿÞÿáÿäÿäÿáÿâÿßÿÞÿáÿãÿàÿßÿàÿàÿÞÿÚÿÛÿ×ÿÕÿØÿØÿ×ÿÚÿÛÿÞÿáÿáÿâÿçÿåÿèÿìÿëÿëÿèÿêÿèÿèÿäÿäÿÞÿßÿàÿàÿÚÿÑÿÕÿÕÿÖÿÖÿ×ÿØÿÙÿÙÿÕÿ×ÿÚÿØÿÚÿØÿØÿÕÿÖÿÕÿÕÿÓÿÒÿÓÿÏÿ×ÿØÿÙÿÚÿßÿÜÿÝÿßÿàÿàÿáÿáÿäÿãÿåÿèÿéÿçÿçÿçÿåÿßÿÝÿÚÿÚÿÛÿÞÿÚÿÚÿàÿäÿàÿàÿàÿÞÿÜÿÚÿáÿàÿÝÿÛÿ×ÿ×ÿ×ÿØÿÜÿÝÿàÿßÿÜÿâÿäÿåÿãÿëÿéÿçÿæÿèÿëÿìÿìÿîÿíÿíÿëÿéÿèÿçÿåÿçÿæÿèÿéÿîÿóÿñÿóÿòÿòÿôÿóÿñÿíÿíÿçÿêÿæÿäÿæÿäÿäÿæÿåÿçÿêÿèÿêÿîÿðÿìÿëÿðÿîÿïÿôÿ÷ÿ÷ÿöÿóÿóÿòÿïÿïÿðÿíÿêÿçÿðÿóÿòÿîÿòÿóÿóÿöÿöÿöÿòÿðÿóÿóÿðÿîÿìÿíÿîÿëÿìÿíÿìÿîÿóÿóÿñÿðÿòÿðÿîÿíÿíÿíÿïÿñÿðÿðÿôÿíÿêÿíÿëÿêÿçÿëÿëÿëÿíÿîÿòÿóÿõÿ÷ÿøÿõÿöÿòÿôÿõÿðÿëÿìÿìÿêÿêÿêÿêÿìÿíÿëÿïÿïÿñÿñÿñÿóÿíÿìÿîÿíÿðÿíÿìÿëÿéÿçÿæÿåÿäÿàÿÞÿÞÿàÿàÿãÿãÿäÿâÿâÿâÿæÿæÿäÿãÿáÿßÿßÿÞÿßÿÙÿÖÿÙÿÜÿÙÿÛÿÜÿÝÿÙÿÙÿÛÿÛÿÚÿÞÿÞÿÝÿâÿâÿáÿàÿàÿàÿÞÿÚÿÖÿÕÿÖÿÖÿÖÿÔÿØÿÙÿÙÿÝÿÝÿßÿãÿâÿáÿÞÿÝÿÛÿÝÿØÿØÿ×ÿÏÿÍÿËÿÍÿÏÿÎÿÓÿÑÿÒÿÕÿÙÿÙÿÚÿÜÿÞÿÛÿàÿâÿàÿâÿãÿÞÿÜÿØÿ×ÿÔÿÒÿÐÿÎÿËÿÌÿÊÿËÿÐÿÔÿÕÿ×ÿ×ÿ×ÿÚÿÙÿÖÿÔÿÕÿÔÿÒÿÑÿÏÿÒÿÐÿÑÿÒÿÕÿÔÿÒÿÑÿÏÿÓÿÖÿ×ÿÔÿÕÿÕÿ×ÿÝÿÝÿÙÿÚÿÛÿÚÿÚÿÖÿÔÿÔÿÏÿÌÿÍÿÍÿÐÿÕÿ×ÿ×ÿ×ÿÙÿÙÿ×ÿÖÿÕÿÖÿÖÿÔÿÑÿÎÿÏÿÍÿÍÿÎÿÍÿÍÿÍÿËÿÍÿÎÿÎÿËÿÊÿÊÿËÿËÿÌÿÐÿÑÿÓÿÔÿÖÿÐÿÍÿÍÿËÿÊÿËÿÉÿÂÿÁÿÆÿÈÿÊÿÊÿËÿÏÿÐÿÓÿÔÿÑÿÕÿÒÿÎÿÐÿÍÿÏÿÒÿÍÿÍÿÌÿËÿÌÿÍÿÌÿÏÿÑÿÏÿÐÿÐÿÐÿÑÿÌÿÏÿÐÿÑÿÓÿÓÿÕÿÓÿÓÿÑÿÐÿÍÿËÿÌÿÊÿÊÿÌÿÍÿÑÿÒÿÔÿÔÿÓÿÒÿÕÿÓÿÓÿÔÿÔÿÏÿÎÿÌÿÎÿÐÿÏÿÒÿÐÿÎÿÌÿÎÿÑÿÒÿÒÿÔÿÔÿÖÿÖÿÓÿÓÿÖÿÙÿØÿÙÿÙÿÖÿ×ÿ×ÿÖÿÑÿÍÿÉÿÉÿÎÿÏÿÍÿÒÿÕÿÓÿÔÿÕÿÕÿÕÿ×ÿÖÿÕÿÕÿÒÿÓÿÔÿÔÿ×ÿÜÿÝÿÜÿÚÿÞÿÞÿÞÿßÿáÿàÿáÿàÿâÿäÿçÿæÿåÿäÿåÿæÿèÿåÿàÿãÿßÿßÿÝÿßÿÝÿàÿáÿåÿéÿéÿíÿîÿóÿïÿíÿëÿíÿëÿèÿçÿåÿèÿçÿçÿëÿîÿìÿîÿñÿóÿõÿóÿùÿùÿöÿøÿûÿûÿùÿ÷ÿúÿýÿýÿûÿ÷ÿõÿóÿöÿõÿ÷ÿùÿÿÿÿÿÿÿÿÿýÿûÿúÿûÿ÷ÿøÿöÿúÿüÿúÿùÿûÿ             üÿüÿÿÿÿÿÿÿþÿþÿÿÿûÿùÿöÿ÷ÿóÿñÿóÿôÿóÿòÿóÿ÷ÿøÿ÷ÿôÿõÿõÿðÿñÿñÿêÿëÿëÿèÿêÿçÿçÿåÿäÿåÿåÿäÿäÿèÿçÿçÿèÿèÿåÿêÿëÿëÿêÿêÿëÿíÿêÿèÿæÿßÿÝÿÙÿÚÿÝÿßÿÞÿáÿáÿãÿäÿèÿâÿåÿåÿãÿÝÿÚÿØÿÕÿÕÿÔÿÖÿØÿÕÿÖÿ×ÿØÿÛÿÚÿÜÿÞÿÞÿÛÿÜÿÜÿ×ÿÚÿÚÿÝÿÛÿÜÿ×ÿÙÿÖÿÒÿÐÿÓÿÔÿÖÿÓÿÒÿÓÿÓÿÓÿÕÿÜÿÞÿÜÿ×ÿ×ÿÙÿÙÿÚÿÞÿÚÿÕÿÖÿÕÿÓÿÔÿÔÿÓÿÖÿØÿÙÿØÿÙÿ×ÿØÿÙÿÖÿÔÿÓÿÒÿÖÿÔÿÓÿÕÿÓÿÔÿÖÿÔÿÏÿÍÿÌÿÍÿÐÿÑÿÓÿÖÿ×ÿØÿÙÿØÿØÿÙÿÙÿØÿÕÿÕÿÔÿÔÿ×ÿÚÿÖÿÕÿÕÿÕÿÓÿÒÿÑÿÕÿÓÿÔÿÕÿÐÿÒÿÕÿÖÿÜÿØÿÖÿØÿ×ÿÓÿÒÿÏÿÌÿÌÿÉÿÊÿÌÿÌÿÊÿÉÿËÿÎÿÓÿÔÿÖÿÓÿÓÿÓÿÕÿÕÿÕÿÏÿÎÿÑÿÒÿÍÿÒÿÐÿÏÿÑÿÐÿÏÿÐÿÓÿÒÿÒÿÕÿÑÿÑÿÑÿÕÿ×ÿÔÿÑÿÔÿÒÿÍÿÍÿËÿÈÿÄÿÂÿÇÿÇÿÆÿÇÿÌÿÌÿÍÿÑÿÏÿÎÿÌÿÌÿÌÿÌÿËÿÌÿÌÿÎÿÌÿÉÿÆÿÃÿÇÿËÿÌÿÍÿÊÿÌÿÎÿÏÿÎÿÑÿÑÿÏÿÐÿÐÿÏÿÎÿÓÿÑÿÎÿÓÿÐÿÏÿÈÿÉÿÅÿÃÿÀÿÄÿÅÿÄÿÁÿÂÿÅÿÊÿÉÿÊÿÉÿÌÿÊÿÉÿÇÿÆÿÅÿÈÿÃÿÂÿÁÿÂÿÃÿÄÿÄÿÅÿÃÿÂÿÄÿÈÿÄÿÅÿÈÿÉÿÍÿÌÿÌÿËÿÉÿÌÿÎÿÉÿÈÿÈÿÄÿÃÿÃÿ¾ÿÆÿÆÿÆÿÅÿÆÿÌÿÍÿÏÿËÿÍÿËÿÊÿÆÿÇÿÃÿÂÿÁÿÃÿÆÿÄÿÄÿÃÿÈÿÈÿÈÿÊÿÎÿÌÿÈÿÍÿÎÿÍÿÉÿÎÿÐÿÏÿÑÿÎÿÍÿÍÿÊÿÌÿÐÿÏÿÌÿÇÿÇÿÍÿËÿÊÿÎÿÐÿÑÿÓÿÑÿÐÿÒÿÔÿÐÿÌÿÍÿÏÿÌÿÍÿËÿÌÿÍÿÍÿÎÿÑÿÏÿÎÿÐÿÏÿÏÿÑÿÐÿÏÿÏÿÓÿÖÿØÿ×ÿÙÿÛÿ×ÿÐÿÐÿÑÿÑÿÑÿÐÿÑÿÏÿÓÿÕÿÖÿØÿÚÿÜÿàÿÝÿÞÿâÿáÿÜÿÞÿÙÿØÿØÿÖÿØÿØÿÔÿÕÿÕÿ×ÿØÿØÿÚÿØÿÛÿÜÿÙÿÛÿáÿáÿáÿßÿÞÿÞÿßÿáÿßÿÜÿÖÿÖÿØÿÙÿÜÿÞÿÞÿàÿßÿâÿåÿãÿâÿåÿåÿéÿïÿïÿëÿêÿçÿåÿçÿëÿíÿïÿïÿíÿñÿðÿñÿòÿñÿòÿóÿöÿõÿùÿýÿüÿûÿþÿþÿýÿ÷ÿùÿ÷ÿôÿóÿóÿ÷ÿ÷ÿúÿûÿüÿþÿþÿ !!! "! %'*/2.,-//075258888988:;:<;=;:>@>ADBBCEBBB@==9<;;;=>??=>BEEIJPNOLGILMPLPRPSPQPONNRPRPRQPNQQSQQQONNOLLKMOQQQPPMQOOMOMNMOOQTVWTW\[\\Z[XUSSRUTTTPNPSPPSVVRRUTVUSTVTQTQLSSPQUUUYWUWVQPMPSRQQQTRSUSWRTSPSWZTSSOQOLEJFFCDGGDHLLLNOLQQLLIGFEEFDDEGGICBHIJJHHILLIGFIGD?=>>;>;=>A@>><:<:<:8>;:975325779464668:=:<857621000/0-.32530,/0,-//0.,,.0-,)*,).,1/,/+++.-.+)%&$$!&#%)-*)+-,+&&))),+*-,))(%(&&%&&'++-+)#!"#$&$!!!###$$$$#"$!"!""'%&""  "#$!"!!# !!  !$%%$!%$   $&$!#%!""" "%% #!    þÿúÿúÿûÿ÷ÿòÿ÷ÿõÿòÿöÿ÷ÿ÷ÿöÿøÿùÿõÿùÿûÿ÷ÿ÷ÿùÿöÿõÿøÿ÷ÿøÿøÿõÿòÿôÿóÿðÿðÿñÿòÿôÿôÿóÿõÿöÿ÷ÿõÿõÿñÿóÿñÿïÿëÿçÿçÿâÿáÿçÿäÿâÿæÿãÿáÿâÿåÿåÿáÿàÿáÿßÿÝÿÝÿßÿÝÿßÿÞÿßÿßÿãÿßÿÞÿÛÿÖÿ×ÿ×ÿÖÿØÿÓÿÕÿÔÿÕÿØÿ×ÿ×ÿ×ÿÕÿÒÿÔÿÓÿÓÿÐÿÍÿÍÿÇÿÌÿËÿÍÿÌÿÏÿÊÿÉÿÉÿÈÿÈÿÉÿÆÿÇÿÄÿÅÿÇÿÆÿÉÿÌÿÍÿÍÿÊÿÎÿÈÿÈÿÈÿÅÿÄÿÇÿÈÿËÿÏÿÎÿÌÿÌÿÈÿÇÿÉÿÇÿÆÿÁÿÁÿÀÿÁÿ¿ÿÁÿÃÿÂÿÂÿÇÿËÿÍÿÍÿËÿÌÿÏÿÐÿÎÿÈÿÊÿÆÿÊÿËÿÌÿËÿÌÿÊÿÇÿÅÿÃÿÅÿÅÿÆÿÃÿÂÿÇÿÅÿÅÿÄÿÅÿÆÿÃÿÃÿÄÿÃÿÂÿ¿ÿ¾ÿ½ÿ½ÿ¹ÿ»ÿºÿºÿ¹ÿ¼ÿ¾ÿ¾ÿ½ÿ¼ÿÄÿ¾ÿ½ÿ½ÿ¿ÿÀÿÃÿÄÿÅÿÄÿÄÿÅÿÌÿÈÿÇÿÉÿÈÿÆÿÅÿÃÿÄÿÈÿÇÿÇÿÈÿÉÿÌÿÊÿÊÿÌÿÌÿÇÿÄÿÄÿÀÿ¾ÿÁÿ¿ÿ¾ÿºÿºÿ»ÿ½ÿ½ÿ½ÿ¿ÿÁÿÂÿÂÿÂÿÅÿÄÿÁÿÀÿÄÿÄÿÇÿÆÿÇÿÈÿÉÿÌÿÊÿÌÿÊÿÈÿÈÿÈÿÉÿÈÿÊÿÊÿÍÿËÿÏÿÐÿÏÿÏÿÎÿËÿÊÿÉÿÆÿÃÿÂÿÅÿÄÿÄÿÉÿËÿËÿËÿÊÿÈÿÇÿÈÿÇÿÆÿÊÿÇÿËÿÈÿÆÿÆÿÆÿËÿËÿÉÿÍÿÎÿÏÿÑÿÐÿÎÿÎÿÏÿÏÿÒÿÓÿÑÿÏÿÒÿÑÿÐÿÍÿÎÿÎÿËÿÆÿÇÿÆÿÃÿÃÿÈÿÆÿÇÿÊÿÊÿÇÿÊÿËÿÊÿÉÿÌÿÉÿËÿÌÿÊÿÉÿÇÿÉÿÈÿÉÿËÿÈÿÊÿÉÿÉÿÉÿÈÿÆÿÉÿÈÿÆÿÌÿÎÿÒÿÐÿËÿËÿÌÿÊÿÇÿÇÿÃÿÂÿÁÿÀÿ¼ÿ¿ÿ¿ÿ¿ÿ¾ÿ¿ÿÁÿÀÿ¿ÿ¾ÿ½ÿ¼ÿ½ÿ¼ÿ¼ÿ½ÿ½ÿ¼ÿ½ÿ¿ÿ¾ÿ»ÿ½ÿÁÿ»ÿ¼ÿ»ÿ¹ÿ¸ÿ¸ÿ¶ÿ¹ÿ·ÿºÿ¼ÿÁÿ¿ÿ¼ÿ¾ÿ¿ÿ¼ÿ½ÿ¹ÿ¸ÿ¶ÿ´ÿ°ÿ±ÿ®ÿ¯ÿ­ÿ°ÿ±ÿ®ÿ®ÿ°ÿ±ÿ°ÿµÿ²ÿ°ÿ®ÿ´ÿµÿ¸ÿ¸ÿ¶ÿ·ÿ¸ÿ·ÿ´ÿ´ÿ±ÿ¶ÿµÿ´ÿ²ÿ³ÿ¯ÿ¯ÿ¯ÿ°ÿ°ÿ²ÿ°ÿ°ÿ®ÿ¬ÿªÿªÿ©ÿ¦ÿ¥ÿ¤ÿ¦ÿ«ÿ§ÿ§ÿ©ÿªÿªÿ¬ÿ®ÿ«ÿ©ÿ¬ÿ¬ÿ®ÿ­ÿ«ÿ¯ÿ°ÿ«ÿ°ÿ²ÿ²ÿ²ÿ¯ÿ°ÿ®ÿ²ÿ°ÿ´ÿ²ÿ²ÿ´ÿ²ÿ³ÿ±ÿ²ÿ°ÿ°ÿ¬ÿ­ÿ©ÿ©ÿ§ÿ¦ÿ¢ÿ£ÿ¤ÿ¤ÿ¥ÿ¦ÿ¥ÿ§ÿ§ÿ¦ÿ¨ÿ§ÿ¨ÿ¯ÿ­ÿ¯ÿ¯ÿ¬ÿ°ÿ¯ÿ²ÿ°ÿ®ÿ¯ÿ°ÿ®ÿ±ÿ³ÿ¯ÿ­ÿ¬ÿ¯ÿ³ÿ²ÿ³ÿ±ÿ´ÿ³ÿ´ÿ²ÿ³ÿ±ÿ¯ÿ°ÿ¬ÿ§ÿ«ÿ©ÿ¦ÿ§ÿ£ÿ¦ÿ¢ÿ¢ÿ£ÿ¤ÿ¥ÿ£ÿ¡ÿ£ÿ£ÿ£ÿ ÿ ÿ£ÿ¡ÿ ÿ£ÿ ÿ£ÿŸÿ ÿžÿ£ÿ¢ÿ¤ÿ¥ÿ¨ÿ§ÿ¦ÿ¥ÿ§ÿ¦ÿ¨ÿ©ÿ­ÿ¯ÿ«ÿªÿ®ÿ¯ÿªÿ¥ÿ¢ÿ¡ÿ¢ÿ¢ÿ¤ÿ ÿÿ›ÿšÿžÿ£ÿ ÿœÿŸÿ ÿŸÿŸÿ ÿ ÿ£ÿ§ÿ¨ÿ®ÿ­ÿ±ÿ¶ÿ³ÿ´ÿ²ÿ±ÿ²ÿ±ÿ¶ÿµÿ²ÿ°ÿ´ÿµÿ²ÿ±ÿµÿµÿ³ÿ°ÿ®ÿ¬ÿ«ÿ¯ÿ­ÿ¬ÿ¬ÿªÿ«ÿ«ÿ­ÿ¬ÿªÿ©ÿ¢ÿ£ÿ§ÿ¤ÿ ÿ¡ÿžÿ¡ÿ¡ÿ¢ÿ¢ÿ¢ÿ¥ÿ£ÿ¡ÿ ÿ¤ÿ¤ÿ¥ÿ¡ÿ¢ÿ¥ÿ§ÿªÿ«ÿªÿªÿ­ÿ´ÿ¯ÿ®ÿ¬ÿ¨ÿ§ÿ¦ÿ¦ÿ¡ÿÿ›ÿÿžÿÿšÿœÿœÿžÿ ÿ ÿžÿžÿ ÿ¡ÿ¤ÿ¥ÿ¦ÿ¦ÿªÿ«ÿ¬ÿ«ÿ«ÿ©ÿ¨ÿ¥ÿ§ÿ¥ÿ¤ÿ§ÿ¨ÿ¨ÿ¦ÿ¨ÿ¨ÿ¬ÿ«ÿ­ÿ¯ÿ°ÿ¬ÿ¬ÿ¤ÿ¥ÿ¤ÿ¢ÿ¡ÿžÿÿ¢ÿ¢ÿŸÿ¢ÿÿœÿšÿ”ÿ—ÿ•ÿ›ÿ˜ÿšÿžÿŸÿ¢ÿ£ÿ¡ÿ£ÿ£ÿ¢ÿ¡ÿ£ÿ¦ÿ§ÿ¥ÿ¢ÿ¤ÿ¤ÿ¤ÿ¤ÿ§ÿ§ÿ©ÿ§ÿ¨ÿ«ÿ¬ÿ­ÿ«ÿ¨ÿ¦ÿ§ÿ¥ÿ¥ÿ§ÿ¥ÿ©ÿ«ÿ¨ÿ¨ÿ¨ÿ«ÿªÿ¬ÿ¨ÿ¬ÿ®ÿ®ÿ¯ÿ±ÿ³ÿ³ÿ°ÿ²ÿ³ÿ²ÿ²ÿ¯ÿ­ÿ®ÿ®ÿªÿ­ÿ°ÿ®ÿ«ÿ¬ÿ°ÿ¯ÿ­ÿ¯ÿ¯ÿ°ÿ²ÿ³ÿ­ÿ«ÿ¬ÿ¬ÿªÿªÿ¦ÿ©ÿªÿ­ÿ§ÿ¦ÿ§ÿ©ÿ¨ÿ§ÿ¨ÿ§ÿ¬ÿ¬ÿ¬ÿ©ÿ¬ÿ«ÿ®ÿ¬ÿªÿ«ÿ±ÿ±ÿ°ÿ­ÿ¯ÿ®ÿ²ÿ°ÿ¯ÿ´ÿ±ÿ³ÿ±ÿ¶ÿ¸ÿ·ÿ´ÿµÿµÿ³ÿ³ÿ²ÿ²ÿ¶ÿ¸ÿ·ÿ·ÿ¸ÿ·ÿºÿ¸ÿ¸ÿ·ÿ·ÿ¶ÿ³ÿ´ÿ´ÿ¸ÿ¸ÿ¶ÿµÿ¶ÿºÿ¾ÿ»ÿ¸ÿ·ÿ·ÿºÿºÿºÿ¶ÿµÿ¶ÿºÿ½ÿÀÿÁÿÄÿÃÿÃÿÃÿÀÿÁÿ¿ÿÁÿ»ÿ¹ÿ¾ÿ»ÿºÿ¸ÿ¹ÿ¹ÿ¸ÿµÿ´ÿ·ÿ¶ÿºÿ¼ÿ½ÿ½ÿ¿ÿÀÿÂÿÀÿÃÿÂÿÄÿÇÿÉÿÉÿÉÿÉÿÈÿÈÿÆÿÇÿÅÿÈÿÉÿÉÿÊÿËÿÊÿÍÿÒÿÐÿÒÿÓÿÓÿÑÿÐÿÒÿÔÿÑÿÒÿÔÿÖÿÕÿÙÿ×ÿÒÿÒÿÓÿÒÿÐÿÏÿÔÿÓÿÓÿÓÿÖÿÚÿÞÿÝÿâÿÛÿÛÿâÿàÿáÿãÿäÿåÿåÿåÿçÿæÿèÿéÿæÿåÿåÿéÿêÿèÿèÿçÿæÿçÿçÿæÿçÿæÿèÿéÿéÿéÿèÿéÿèÿçÿêÿêÿëÿéÿéÿðÿñÿõÿøÿöÿ÷ÿóÿóÿõÿùÿùÿöÿ÷ÿùÿùÿøÿøÿöÿüÿøÿøÿúÿøÿ÷ÿùÿ÷ÿöÿöÿòÿîÿóÿõÿóÿöÿïÿïÿìÿïÿðÿîÿñÿòÿõÿõÿöÿöÿ÷ÿúÿýÿþÿÿÿþÿÿÿýÿÿÿýÿûÿüÿüÿúÿúÿ              !$# ##$$$%%!$&$!!  ! "!$"#&,*(*((()*/..-0-,.10231..231/1010.-,*.,0/+001//4435658<>@>ADDD=>?CC@?<>>;;9950231356<;=>AAABAGIDDCEBBEFDDFFFCEGHKIEEGHHGFBB@?<777979598;:::59==?==>?>A>A>?=727434259::::963741///013651021,--.011/2312352420/1/0/-)+),*(()#%#! !!" !"$&(')*%"&'""         ûÿþÿúÿûÿøÿøÿùÿùÿöÿóÿóÿ÷ÿöÿöÿùÿ÷ÿúÿúÿùÿ÷ÿõÿôÿôÿõÿóÿôÿ÷ÿòÿõÿ÷ÿúÿõÿõÿõÿöÿõÿõÿøÿøÿøÿõÿòÿôÿôÿ÷ÿøÿ÷ÿóÿñÿëÿëÿìÿëÿêÿëÿëÿìÿñÿðÿìÿíÿëÿìÿîÿïÿñÿóÿðÿòÿïÿëÿèÿéÿêÿèÿíÿêÿíÿîÿíÿëÿìÿêÿçÿéÿëÿëÿíÿîÿëÿíÿëÿçÿçÿêÿéÿæÿâÿåÿäÿåÿäÿçÿæÿæÿæÿåÿçÿéÿéÿíÿìÿíÿíÿêÿëÿéÿìÿêÿèÿçÿäÿæÿãÿçÿçÿêÿèÿæÿçÿæÿçÿäÿæÿãÿçÿæÿçÿæÿéÿåÿãÿâÿâÿÝÿßÿáÿáÿáÿåÿçÿèÿéÿèÿëÿìÿíÿîÿëÿñÿîÿîÿîÿïÿîÿíÿðÿïÿðÿòÿòÿòÿóÿóÿñÿðÿïÿðÿóÿóÿòÿòÿñÿóÿóÿòÿíÿïÿïÿíÿîÿïÿïÿîÿéÿëÿïÿñÿîÿñÿòÿòÿôÿòÿñÿðÿïÿïÿðÿðÿôÿöÿ÷ÿóÿòÿóÿöÿ÷ÿúÿøÿöÿ÷ÿõÿõÿöÿñÿîÿïÿðÿðÿôÿñÿîÿìÿèÿèÿêÿêÿçÿèÿèÿìÿîÿðÿïÿòÿóÿòÿöÿóÿóÿòÿñÿóÿõÿöÿóÿùÿùÿøÿ÷ÿöÿûÿüÿ÷ÿöÿõÿøÿùÿöÿòÿöÿõÿ÷ÿôÿôÿñÿôÿõÿöÿôÿõÿôÿðÿðÿñÿðÿïÿïÿìÿéÿíÿíÿîÿîÿñÿïÿïÿðÿóÿóÿôÿöÿ÷ÿøÿöÿ÷ÿýÿùÿùÿùÿûÿûÿüÿüÿ÷ÿùÿöÿöÿôÿõÿ÷ÿôÿõÿóÿõÿöÿôÿõÿóÿôÿ÷ÿùÿùÿùÿ÷ÿúÿýÿüÿýÿúÿÿÿÿÿÿÿýÿüÿþÿüÿûÿýÿÿÿüÿþÿûÿüÿýÿýÿÿÿýÿÿÿÿÿÿÿÿÿþÿüÿûÿûÿúÿúÿøÿõÿùÿøÿùÿüÿýÿÿÿüÿþÿýÿÿÿþÿþÿÿÿüÿÿÿþÿþÿÿÿýÿüÿúÿúÿøÿüÿýÿÿÿÿÿ ÿÿÿÿÿÿüÿûÿûÿûÿúÿýÿüÿüÿúÿúÿþÿüÿþÿÿÿÿÿ ÿÿÿÿ     "  #"##!"$%&%#"'&&''$&&%%%" ##$&&)')*,*/+,*,*--1+*((*-,+),(()***'+)(&&''&%''%()*&*)**,++--10,)+/0/0/.-+.-/00//02.1.,.,*),+,--,-0/.0.44.265674633576540201/015426866321,/1,,+-/.-/2131152556;=9;988:;<9;;:89>824411//2.-.//0./-12235997::7:>?<:9697:6967;634464356543/1222-++-.-.0.--20/230./1.*).-,-.*)*,'+),+''$#" !""!!"!! "#!"!&% ! $       üÿþÿÿÿÿÿÿÿþÿÿÿüÿüÿùÿÿÿúÿ÷ÿöÿ÷ÿóÿ÷ÿöÿôÿôÿ÷ÿöÿøÿúÿûÿ÷ÿ÷ÿøÿøÿøÿûÿ÷ÿûÿøÿôÿùÿöÿôÿòÿóÿóÿóÿøÿõÿòÿóÿòÿòÿíÿîÿîÿðÿïÿíÿíÿìÿíÿíÿïÿðÿíÿëÿéÿêÿìÿëÿëÿêÿêÿéÿìÿéÿéÿçÿçÿçÿæÿëÿíÿìÿëÿçÿëÿïÿëÿìÿîÿîÿíÿëÿíÿîÿîÿêÿëÿèÿéÿêÿæÿäÿéÿèÿäÿçÿäÿäÿæÿèÿåÿäÿäÿàÿãÿâÿèÿåÿçÿçÿæÿäÿäÿàÿäÿáÿàÿàÿßÿÜÿÜÿÜÿáÿàÿÞÿßÿÞÿâÿãÿáÿßÿâÿçÿæÿçÿâÿãÿäÿåÿãÿáÿÜÿáÿâÿàÿàÿÜÿãÿæÿãÿàÿäÿäÿåÿåÿäÿåÿåÿæÿáÿáÿáÿàÿÝÿÝÿÙÿÛÿÛÿÞÿÝÿÜÿÚÿÛÿÛÿÝÿÚÿÝÿÞÿßÿÞÿÜÿÙÿÛÿÛÿÖÿÙÿÚÿÛÿÝÿÜÿÙÿ×ÿÖÿÚÿ×ÿÕÿÔÿÕÿÙÿ×ÿÙÿØÿÖÿÕÿ×ÿÕÿÓÿÒÿÒÿÎÿÎÿÑÿÓÿÔÿÐÿÓÿÒÿÌÿÏÿÑÿÍÿÎÿÍÿÊÿËÿÎÿÉÿÉÿÈÿÆÿÅÿÅÿÆÿÃÿ¿ÿ¾ÿ¿ÿÁÿÂÿÂÿÁÿÂÿÂÿÂÿÅÿÊÿÊÿÉÿÆÿÈÿÇÿÊÿÇÿÅÿÅÿÆÿÃÿÁÿÀÿÂÿ½ÿºÿ¹ÿ¸ÿºÿºÿ½ÿ¼ÿ½ÿ¼ÿ¾ÿ¾ÿ¾ÿ½ÿ¸ÿ¶ÿ¸ÿ¶ÿ¶ÿ·ÿ¹ÿºÿ·ÿ´ÿ³ÿ¶ÿµÿ±ÿ¯ÿ°ÿ¯ÿ²ÿ¶ÿ·ÿ»ÿ¹ÿ¸ÿºÿ¹ÿ¸ÿ¼ÿºÿ¶ÿ¹ÿ·ÿ·ÿ³ÿ´ÿ¼ÿºÿ¸ÿ»ÿ½ÿºÿ¾ÿ»ÿ¹ÿ½ÿ¹ÿ·ÿµÿ¶ÿ´ÿ³ÿ¸ÿ¹ÿ¸ÿ·ÿµÿ´ÿ²ÿ´ÿ·ÿ¶ÿ·ÿµÿ´ÿ¶ÿ¸ÿµÿ¶ÿ²ÿ¹ÿ¹ÿ»ÿ¼ÿ¼ÿºÿ»ÿºÿºÿ»ÿµÿ´ÿ´ÿ³ÿ¶ÿ»ÿ¼ÿ½ÿ¿ÿ¾ÿ»ÿ¿ÿÁÿÁÿÀÿ¾ÿÀÿÂÿ¿ÿ¿ÿ¾ÿ½ÿ¾ÿ¾ÿÀÿ¿ÿÁÿÀÿ¿ÿÂÿÆÿÈÿÂÿÇÿÊÿËÿÍÿÏÿÏÿÏÿÑÿÑÿÐÿÐÿÏÿÎÿÍÿÇÿÊÿÊÿÇÿËÿÌÿÌÿÎÿÎÿËÿÊÿÌÿÌÿËÿÈÿÉÿÌÿÎÿÍÿÎÿÏÿÏÿËÿÍÿÍÿÐÿÍÿÎÿÐÿÑÿÑÿÒÿÕÿÔÿÑÿÔÿ×ÿØÿÕÿÙÿ×ÿÙÿÛÿÚÿÛÿÚÿÖÿÕÿÕÿØÿ×ÿÛÿÝÿÛÿ×ÿÞÿßÿÝÿÜÿâÿàÿÞÿÙÿÖÿØÿÜÿÞÿÛÿÚÿÚÿÜÿÜÿÜÿÜÿÞÿãÿçÿäÿåÿäÿäÿåÿçÿçÿêÿìÿëÿìÿíÿîÿëÿéÿêÿéÿìÿïÿìÿñÿðÿòÿñÿïÿðÿïÿòÿôÿõÿôÿðÿòÿïÿðÿôÿïÿíÿïÿéÿêÿðÿðÿñÿòÿõÿõÿõÿóÿôÿõÿøÿýÿþÿþÿÿÿþÿþÿùÿøÿûÿýÿýÿþÿþÿüÿþÿþÿÿÿþÿþÿÿÿýÿüÿûÿûÿûÿúÿúÿûÿýÿþÿþÿüÿþÿÿÿ                               $$"!#!$'# !!%$!$%&()'#!%'(%&$#$'&%%"%&#$#!"%&$(,-))&'&()&#(%#!$(#%$%%&%$"'')%% "!!#%#$%%"          ûÿÿÿüÿùÿûÿúÿøÿùÿúÿùÿúÿøÿøÿúÿýÿýÿýÿûÿúÿûÿùÿ÷ÿ÷ÿùÿøÿøÿøÿùÿöÿøÿøÿ÷ÿúÿúÿöÿôÿ÷ÿôÿõÿøÿõÿñÿðÿóÿóÿïÿðÿïÿíÿìÿíÿêÿëÿïÿðÿîÿóÿòÿõÿöÿ÷ÿôÿöÿùÿûÿùÿõÿòÿðÿòÿïÿíÿïÿðÿðÿóÿñÿôÿòÿöÿõÿóÿñÿôÿòÿîÿìÿìÿëÿíÿìÿìÿìÿëÿêÿéÿæÿèÿèÿíÿéÿêÿðÿñÿíÿïÿîÿìÿïÿïÿïÿðÿðÿòÿîÿñÿðÿëÿëÿéÿêÿëÿìÿðÿðÿñÿöÿôÿðÿîÿðÿòÿóÿòÿïÿðÿóÿòÿñÿôÿóÿðÿñÿðÿðÿðÿîÿñÿòÿóÿóÿ÷ÿ÷ÿøÿùÿûÿùÿýÿýÿûÿùÿõÿöÿöÿüÿüÿüÿûÿùÿøÿ÷ÿøÿýÿÿÿÿÿÿÿÿÿþÿÿÿ $%!!$%(&$%$())**&%'%(&()%))**+()*/+*+)()$%%$$&(*-/.-030-.0+++0---.1/+//1221/,),-.,.-*+*)*,.,+))%&'*+-)())*+**(''(+)&$&%$"%$%""!%! #"!# #$''       þÿþÿûÿùÿüÿùÿùÿúÿûÿýÿûÿùÿöÿøÿúÿøÿôÿùÿúÿüÿýÿÿÿþÿþÿúÿùÿûÿúÿúÿôÿòÿóÿøÿúÿøÿöÿôÿõÿúÿùÿúÿõÿöÿõÿñÿðÿîÿôÿõÿõÿòÿôÿóÿõÿôÿõÿôÿñÿóÿùÿöÿôÿóÿòÿöÿùÿùÿùÿùÿöÿôÿõÿ÷ÿ÷ÿ÷ÿøÿùÿ÷ÿ÷ÿõÿôÿôÿòÿöÿõÿòÿòÿõÿôÿõÿõÿñÿóÿôÿñÿòÿñÿïÿñÿðÿîÿðÿíÿíÿíÿíÿëÿïÿéÿéÿïÿîÿïÿíÿíÿïÿòÿôÿôÿòÿòÿñÿòÿóÿóÿöÿõÿôÿöÿùÿüÿúÿýÿúÿùÿúÿùÿúÿùÿ÷ÿöÿøÿ÷ÿûÿþÿûÿûÿüÿýÿüÿýÿþÿþÿÿÿþÿÿÿÿÿüÿüÿúÿüÿÿÿýÿþÿÿÿüÿþÿüÿýÿüÿüÿýÿýÿÿÿüÿûÿúÿùÿúÿøÿõÿøÿ÷ÿóÿíÿòÿóÿõÿøÿ÷ÿ÷ÿ÷ÿüÿüÿùÿúÿùÿùÿüÿúÿúÿøÿúÿúÿøÿùÿ÷ÿôÿ÷ÿøÿöÿóÿõÿôÿñÿõÿóÿòÿõÿôÿ÷ÿøÿöÿøÿ÷ÿ÷ÿøÿõÿóÿôÿóÿôÿñÿòÿóÿöÿ÷ÿùÿûÿøÿ÷ÿõÿöÿúÿøÿøÿ÷ÿøÿöÿóÿ÷ÿõÿôÿôÿôÿõÿøÿøÿõÿõÿøÿ÷ÿóÿôÿòÿðÿðÿôÿðÿóÿóÿòÿòÿóÿñÿõÿôÿôÿïÿòÿóÿôÿôÿöÿôÿòÿôÿùÿùÿ÷ÿúÿÿÿüÿüÿúÿýÿúÿûÿøÿúÿüÿÿÿýÿþÿüÿÿÿÿÿÿÿþÿþÿüÿüÿüÿýÿüÿûÿûÿýÿüÿûÿúÿþÿýÿþÿýÿûÿÿÿÿÿÿÿþÿýÿýÿüÿþÿ ÿÿÿÿ                                       ÿÿþÿûÿþÿýÿýÿÿÿÿÿþÿüÿøÿøÿùÿ÷ÿúÿûÿûÿúÿùÿöÿùÿôÿóÿôÿôÿ÷ÿôÿñÿôÿòÿñÿðÿìÿêÿëÿíÿìÿèÿèÿêÿéÿæÿæÿçÿçÿåÿäÿæÿäÿæÿèÿåÿäÿäÿâÿäÿâÿßÿßÿÞÿßÿäÿßÿàÿßÿâÿàÿàÿÞÿÝÿßÿßÿÛÿÜÿÞÿÚÿÚÿÝÿÚÿÚÿÚÿÙÿ×ÿÖÿØÿØÿÔÿÔÿØÿØÿÓÿÔÿÑÿÏÿÑÿÏÿÐÿÐÿÐÿÏÿÏÿÎÿÌÿÎÿËÿÊÿÇÿËÿÊÿÊÿËÿÏÿÎÿÎÿÎÿÉÿÉÿËÿÉÿÇÿÈÿËÿÉÿÇÿÅÿÄÿÂÿÆÿÇÿÈÿÈÿÂÿÃÿ¾ÿÀÿÄÿÁÿÁÿÂÿÅÿÃÿÂÿÁÿ¿ÿ¾ÿ¿ÿ¿ÿ¿ÿÀÿÁÿÂÿÂÿ½ÿ½ÿÁÿÁÿ¾ÿ¼ÿ½ÿ½ÿºÿ½ÿÀÿ¾ÿ¿ÿÀÿ½ÿ¾ÿ¼ÿºÿ»ÿºÿ¾ÿ¿ÿ¾ÿÁÿÁÿÁÿÄÿÆÿÆÿÂÿÂÿÆÿÃÿÄÿÃÿÅÿÆÿÅÿÆÿÆÿÆÿÃÿÂÿÃÿÅÿÅÿÈÿÌÿËÿÌÿÌÿÏÿÐÿÏÿÐÿÏÿÍÿÏÿÒÿÏÿÐÿÓÿÐÿÐÿÏÿÐÿÏÿÓÿÒÿÐÿÏÿÎÿÐÿÍÿÍÿÎÿÎÿÍÿÍÿÒÿÒÿÏÿÑÿÑÿÐÿÓÿÔÿÑÿÐÿÒÿÔÿÔÿÑÿÓÿ×ÿÖÿØÿÚÿÛÿÛÿÚÿÚÿÜÿØÿÙÿÚÿÜÿÜÿÚÿÜÿÜÿÞÿßÿÞÿÜÿÞÿáÿâÿßÿáÿàÿÞÿàÿâÿäÿâÿåÿãÿãÿçÿçÿçÿæÿåÿæÿçÿãÿäÿãÿæÿæÿçÿéÿëÿæÿèÿìÿêÿîÿìÿïÿìÿíÿêÿëÿïÿñÿïÿîÿðÿòÿòÿðÿîÿíÿîÿóÿòÿðÿïÿîÿðÿñÿóÿöÿôÿôÿïÿóÿúÿøÿøÿúÿùÿùÿúÿúÿöÿöÿöÿùÿøÿùÿ÷ÿøÿøÿúÿýÿÿÿüÿ÷ÿ÷ÿùÿýÿÿÿÿÿüÿýÿýÿ          ÿÿÿÿÿÿÿÿþÿûÿþÿûÿøÿøÿûÿûÿûÿüÿþÿýÿþÿûÿúÿúÿÿÿýÿüÿûÿøÿøÿúÿ÷ÿúÿøÿùÿùÿõÿöÿóÿõÿ÷ÿôÿóÿöÿõÿõÿôÿôÿòÿóÿóÿóÿòÿñÿôÿõÿóÿóÿöÿóÿóÿôÿõÿóÿðÿðÿðÿîÿíÿíÿèÿìÿîÿîÿïÿíÿíÿíÿîÿìÿíÿìÿìÿëÿéÿèÿéÿíÿíÿîÿîÿìÿìÿêÿêÿèÿéÿæÿçÿæÿèÿèÿéÿëÿíÿíÿëÿìÿîÿíÿêÿîÿîÿìÿêÿíÿîÿíÿîÿêÿëÿëÿîÿðÿðÿìÿêÿèÿëÿëÿçÿäÿæÿçÿæÿäÿâÿåÿéÿéÿèÿíÿëÿìÿîÿîÿíÿîÿîÿìÿðÿïÿìÿîÿñÿïÿíÿìÿëÿêÿèÿéÿéÿìÿìÿéÿëÿíÿîÿðÿïÿïÿìÿíÿîÿïÿðÿðÿïÿñÿòÿðÿïÿñÿíÿíÿìÿéÿêÿìÿêÿìÿíÿéÿéÿìÿìÿéÿèÿíÿìÿêÿèÿêÿéÿëÿíÿêÿêÿëÿíÿìÿíÿëÿíÿëÿêÿíÿçÿçÿçÿéÿéÿêÿèÿìÿêÿëÿïÿìÿéÿìÿìÿëÿìÿîÿîÿïÿíÿíÿòÿôÿðÿíÿïÿðÿñÿïÿðÿíÿîÿïÿïÿðÿïÿñÿñÿïÿìÿîÿîÿìÿìÿìÿèÿèÿîÿðÿíÿíÿïÿêÿëÿíÿïÿíÿìÿíÿëÿéÿíÿìÿêÿìÿìÿíÿíÿíÿîÿíÿêÿèÿçÿìÿïÿîÿêÿêÿëÿëÿìÿêÿéÿíÿíÿìÿêÿëÿéÿèÿèÿçÿåÿãÿåÿäÿåÿçÿãÿãÿãÿãÿãÿàÿàÿãÿßÿßÿßÿãÿáÿÞÿãÿãÿãÿâÿáÿßÿáÿæÿåÿäÿáÿàÿßÿÜÿÜÿÞÿÛÿÚÿÝÿÝÿÜÿÛÿÛÿÜÿÛÿÜÿáÿâÿáÿßÿÞÿÛÿÚÿÝÿÞÿÜÿÜÿÛÿÚÿÙÿÕÿ×ÿÖÿÕÿÒÿÕÿÔÿÖÿÖÿÕÿÙÿ×ÿÕÿÖÿØÿÜÿÛÿÔÿÕÿ×ÿÙÿÖÿ×ÿÖÿÔÿÑÿÙÿÙÿ×ÿØÿØÿÖÿÚÿÚÿÙÿÙÿÙÿÕÿÖÿÑÿÕÿÒÿÔÿÕÿÔÿÏÿÏÿÑÿÌÿÉÿÌÿËÿÊÿÊÿÌÿÈÿÇÿÇÿÈÿÇÿÇÿÅÿÅÿÀÿÂÿÃÿÅÿÄÿÅÿÁÿ¿ÿÁÿÀÿÀÿÀÿ¼ÿ¾ÿ¼ÿ½ÿ½ÿÀÿ¾ÿ¼ÿ»ÿ½ÿ»ÿ¹ÿ»ÿ»ÿ·ÿºÿ·ÿµÿ¶ÿ¶ÿµÿ´ÿ²ÿ³ÿ³ÿ²ÿ²ÿ±ÿ±ÿ²ÿ±ÿ³ÿ±ÿ®ÿ°ÿ°ÿ­ÿªÿªÿ­ÿ®ÿ­ÿ®ÿ®ÿªÿ«ÿ¬ÿ±ÿ¯ÿ°ÿ°ÿ¬ÿ«ÿ®ÿ¯ÿ¯ÿ±ÿ°ÿ®ÿ°ÿ­ÿ­ÿ¬ÿ®ÿ®ÿ³ÿ°ÿ±ÿ¬ÿ¬ÿ®ÿ¨ÿ¦ÿ¨ÿ¨ÿ¦ÿ¨ÿªÿ«ÿ¤ÿ¦ÿ§ÿ¨ÿ¤ÿ§ÿ¨ÿ§ÿ¥ÿ§ÿ©ÿ¤ÿ©ÿªÿ¢ÿ¤ÿ¤ÿ¥ÿ§ÿ¥ÿ¤ÿ¥ÿ©ÿ©ÿ©ÿ©ÿ©ÿ¦ÿ¦ÿ¦ÿ§ÿ©ÿ§ÿ¦ÿ¥ÿ§ÿ¦ÿ¨ÿªÿ§ÿ¨ÿ«ÿ©ÿªÿ­ÿ§ÿ©ÿ¨ÿ§ÿ§ÿ©ÿ©ÿ©ÿ¨ÿ¦ÿ©ÿ§ÿ©ÿ©ÿªÿ©ÿ­ÿ¬ÿ­ÿ±ÿ²ÿ±ÿ°ÿ²ÿ±ÿµÿ´ÿ¶ÿ³ÿµÿ·ÿ´ÿµÿµÿ³ÿ·ÿ¶ÿ±ÿ³ÿ·ÿ·ÿµÿ»ÿ¼ÿ½ÿ¾ÿ¿ÿ¾ÿ»ÿ¼ÿ½ÿ»ÿÀÿ¾ÿ¿ÿ¼ÿÁÿÀÿ¾ÿÀÿÀÿ¼ÿ¾ÿ½ÿ¼ÿ½ÿ¼ÿÀÿÁÿÃÿ¾ÿÀÿ½ÿÂÿÀÿÂÿÄÿÆÿÃÿÅÿÃÿÅÿÃÿÅÿÊÿÍÿÊÿÆÿÅÿÇÿÇÿÆÿÇÿÆÿÇÿÆÿÆÿÈÿÆÿÁÿÃÿÇÿËÿÈÿÈÿÇÿÃÿÇÿÅÿÄÿÄÿÃÿÇÿÊÿÌÿÉÿËÿÊÿÊÿÏÿÎÿÏÿÐÿÐÿÏÿÒÿÒÿÏÿÎÿÒÿÒÿÒÿÐÿÏÿÏÿÏÿÍÿÑÿÓÿÑÿÒÿÐÿÐÿÑÿÓÿØÿÖÿÖÿÖÿÓÿÒÿÏÿÏÿÏÿÏÿÒÿÑÿØÿÛÿØÿ×ÿÚÿÙÿ×ÿ×ÿ×ÿÛÿÜÿÚÿÜÿÝÿÞÿÝÿßÿßÿáÿãÿäÿâÿãÿäÿäÿâÿáÿâÿâÿãÿæÿãÿãÿãÿãÿäÿäÿæÿéÿçÿæÿæÿèÿèÿëÿëÿëÿèÿìÿêÿéÿìÿïÿïÿîÿîÿñÿñÿóÿòÿøÿöÿôÿôÿöÿôÿöÿùÿ÷ÿúÿÿÿûÿûÿýÿÿÿÿÿþÿÿÿÿÿ                                            !!! #%%"$('"#&"!&#!'"%%"$%%$!! #""%&$$%%%'%'%$$*'()%(,*)+,-++-/..---,1/1.,-0-.**+/+),,*&&'*(-./22011341222347777346534444341/0430113223002456453102446:35767;667::9;9534210230/111441134/230(,///0..+**,.,-,,+)(+,,,*',,/0/2,,-0-.141/,+*--))-,3.24132--.20..//1.22///0+/0*.0/+*(',.+.**')+(''%()(&('((-,(%&('&)*)+((*('*)%$')%()*&(*+*,))(-,/0,-,,),.*.-1.-/122-0-/41//.++-11/,*-1/-0+)(.0-+*+-2*,/-,++.-+)+()+-...-(+*)(*)**-)+)*(,++(*'((((('*%((*'%&**,++'&**+))()*%((*,,0.+)%%$$)'+.)(&(('+*+,-+)&+,+clam-1.4.0/test/Visualization/StdioSinTracksPresentation.hxx0000644000000000000000000000420510610720021022765 0ustar rootroot#ifndef __STDIOSINTRACKSPRESENTATION__ #define __STDIOSINTRACKSPRESENTATION__ #include "Presentation.hxx" #include "Array.hxx" #include "Slotv1.hxx" #include "Slotv2.hxx" #include "DataTypes.hxx" #include "SinTrackListBuilder.hxx" #include namespace CLAMVM { using SigSlot::Slotv1; using SigSlot::Slotv2; using CLAM::Array; using CLAM::TData; using CLAM::TTime; using CLAM::TSize; class SinTracksModel; class StdioSinTracksPresentation : public Presentation { private: class dump_to_stdout { public: dump_to_stdout() : real_track_id ( 1 ) { } void operator()( const SinusoidalTrack& st ); private: TIndex real_track_id; }; class decimate_sine_tracks { public: decimate_sine_tracks( TSize min_len ) : minimum_len( min_len ) { } void operator() ( SineTrackList& tl ) { SineTrackList::iterator i, end, aux; i = tl.begin(); end = tl.end(); while ( i != end ) { if ( i->size() < minimum_len ) { aux = i; i++; tl.erase( aux ); } i++; } } private: TSize minimum_len; }; protected: typedef SineTrackList::iterator iterator; SineTrackList* mSineTracks; TData mSpectralRange; TTime mBeginTime; TTime mEndTime; TTime mLen; protected: virtual void OnNewTrackList( SineTrackList& array, TSize framelen ); virtual void OnNewRange ( TData spec_rng ); virtual void OnNewDuration( TTime begin, TTime end ); public: Slotv2< SineTrackList&, TSize > SetPartials; Slotv1< TData > SetSpectralRange; Slotv2< TTime, TTime > SetDuration; StdioSinTracksPresentation(); virtual ~StdioSinTracksPresentation(); virtual void AttachTo( SinTracksModel& ); virtual void Detach(); virtual void Show(); virtual void Hide(); }; } #endif // StdioSinTracksPresentation.hxx clam-1.4.0/test/Visualization/StdioSpectralPeakArrayPresentation.cxx0000644000000000000000000000263710610720021024443 0ustar rootroot#include "StdioSpectralPeakArrayPresentation.hxx" #include "SpectralPeaksModel.hxx" #include #include namespace CLAMVM { StdioSpectralPeakArrayPresentation::StdioSpectralPeakArrayPresentation() { SetPartials.Wrap( this, &StdioSpectralPeakArrayPresentation::OnNewPartials ); } StdioSpectralPeakArrayPresentation::~StdioSpectralPeakArrayPresentation() { } void StdioSpectralPeakArrayPresentation::Show() { std::cout << "DATA RETRIEVED: " << std::endl; for ( int i = 0; i < mPartialsToDraw.Size(); i++ ) { std::cout << "Peak #" << i+1 << std::endl; std::cout << "Magnitude (dB): " << mPartialsToDraw[i].mMag << std::endl; std::cout << "Frequency (Hz): " << mPartialsToDraw[i].mFreq << std::endl; std::cout << "Phase (rad):" << mPartialsToDraw[i].mPhase << std::endl; } } void StdioSpectralPeakArrayPresentation::Hide() { } void StdioSpectralPeakArrayPresentation::AttachTo( SpectralPeaksModel& peakModel ) { peakModel.ObjectPublished.Connect( SetPartials ); } void StdioSpectralPeakArrayPresentation::Detach() { SetPartials.Unbind(); } void StdioSpectralPeakArrayPresentation::OnNewPartials( const Array& array ) { mPartialsToDraw.Resize( array.Size() ); mPartialsToDraw.SetSize( array.Size() ); std::copy( array.GetPtr(), array.GetPtr()+array.Size(), mPartialsToDraw.GetPtr() ); } } clam-1.4.0/test/Visualization/DummyTDWidget.hxx0000644000000000000000000000072410610720021020156 0ustar rootroot#ifndef __DUMMYTDWIDGET__ #define __DUMMYTDWIDGET__ #include "InControlPresentation.hxx" namespace CLAMVM { class DummyTDWidget : public InControlPresentation { public: DummyTDWidget(); ~DummyTDWidget(); void EmitValue( TControlData value ); virtual void Show(); virtual void Hide(); protected: virtual void OnNewValue( TControlData value ); virtual void OnNewRange( TControlData min, TControlData max ); }; } #endif // DummyTDWidget.hxx clam-1.4.0/test/Visualization/TestFl_FundFreq.cxx0000644000000000000000000000407210610720021020455 0ustar rootroot#include #include "Segment.hxx" #include "FundamentalAdapter.hxx" #include "WidgetTKWrapper.hxx" #include "XMLStorage.hxx" #include "Err.hxx" #include "Fl_FundFreq.hxx" #include #include #include #include static std::string sFilename; bool TestBasicUseCase( CLAMVM::FundamentalAdapter& adapter, CLAMVM::Fl_FundFreq& presentation ) { CLAM::XMLStorage x; CLAM::Segment segment; x.Restore( segment, sFilename ); std::cout << "SEGMENT RESTORED" << std::endl; adapter.BindTo( segment ); adapter.Publish(); Fl_Window* mainWindow = new Fl_Window( 100, 100, 640, 480, "Test" ); mainWindow->add( &presentation ); mainWindow->end(); mainWindow->show(); CLAMVM::WidgetTKWrapper& tk = CLAMVM::WidgetTKWrapper::GetWrapperFor("FLTK"); tk.Run(); return true; } int main ( int argc, char** argv ) { try { const char* str = fl_file_chooser( "Please, select analysis data", "*.xml", NULL ); if ( !str ) { std::cout << "No file was given!" << std::endl; exit(-1); } sFilename = str; CLAMVM::FundamentalAdapter adapter; CLAMVM::Fl_FundFreq widget( 0,0,640, 480, "Test Fl_FundFreq presentation"); adapter.TrajectoryExtracted.Connect( widget.NewTrajectory ); adapter.TimeSpanChanged.Connect( widget.NewTimeSpan ); std::cerr << "Basic Fl_FundFreq use case test launched" << std::endl; if ( !TestBasicUseCase( adapter, widget ) ) std::cerr << "Basic Use case Test...... FAILED!" << std::endl; else std::cerr << "Basic Use case Test...... Passed!" << std::endl; } catch ( CLAM::Err& e ) { std::cerr << "A CLAM controlled error has occured" << std::endl; e.Print(); std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( std::exception& e ) { std::cerr << "An standard library error has occured" << std::endl; std::cerr << e.what() << std::endl; std::cerr << "<==== END OF ERROR MESSAGE" << std::endl; return -1; } catch( ... ) { std::cerr << "An unknown error has occured!" << std::endl; return -1; } return 0; } clam-1.4.0/test/Visualization/DummyFDFWidget.hxx0000644000000000000000000000234710610720021020251 0ustar rootroot#ifndef __DUMMYFDFWIDGET__ #define __DUMMYFDFWIDGET__ #include "ProcessingControlsPresentation.hxx" #include "ProcessingInControlSet.hxx" #include "InputControlModel.hxx" #include "Signalv1.hxx" #include "Slotv2.hxx" namespace CLAMVM { using SigSlot::Signalv1; using SigSlot::Slotv2; class DummyFDFWidget : public ProcessingInControlsPresentation { public: DummyFDFWidget(); virtual ~DummyFDFWidget(); void Show(); void Hide(); void AttachTo( ProcessingInControlSet& s ); void Detach(); Signalv1 SendGain; Signalv1 SendLowCutoff; Signalv1 SendHighCutoff; Signalv1 SendStopBand; Signalv1 SendPassBand; Slotv2 ReceiveLowCutoffRange; Slotv2 ReceiveHighCutoffRange; Slotv2 ReceiveGainRange; protected: void _OnNewLowCutoffRange( CLAM::TControlData min, CLAM::TControlData max ); void _OnNewHighCutoffRange( CLAM::TControlData min, CLAM::TControlData max ); void _OnNewGainRange( CLAM::TControlData min, CLAM::TControlData max ); }; } #endif // DummyFDFWidget.hxx clam-1.4.0/test/README.txt0000644000000000000000000000010511160752103013573 0ustar rootrootThis directory should contain dedicated tests for the CLAM-Classes clam-1.4.0/test/UnitTests/0000755000000000000000000000000011344231440014043 5ustar rootrootclam-1.4.0/test/UnitTests/PortsTests/0000755000000000000000000000000011344231437016203 5ustar rootrootclam-1.4.0/test/UnitTests/PortsTests/PortsTest.cxx0000644000000000000000000004340210223014174020671 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ //DEPRECATED TO REMOVE // #include #include "cppUnitHelper.hxx" // needed for assertion_traits #include "InPort.hxx" #include "InPort.hxx" #include "OutPort.hxx" #include "OutPort.hxx" #include "Processing.hxx" #include "DummyProcessingData.hxx" namespace CLAMTest { class PortsTest; CPPUNIT_TEST_SUITE_REGISTRATION( PortsTest ); class PortsTest : public CppUnit::TestFixture, public CLAM::Processing { CPPUNIT_TEST_SUITE( PortsTest ); // Tests for the Port base interface: //InPorts CPPUNIT_TEST( testInPort_Attach_WithGeneralTemplateInPort_UpdatesConcretePortState ); CPPUNIT_TEST( testInPort_Attach_WithGeneralTemplateInPort_BadTypeAssertionFails ); CPPUNIT_TEST( testInPort_IsAttached_WithGeneralTemplateInPort_AfterConstruction ); CPPUNIT_TEST( testInPort_IsAttached_WithGeneralTemplateInPort_AfterAttach ); CPPUNIT_TEST( testInPort_IsAttached_WithGeneralTemplateInPort_AfterUnattach ); CPPUNIT_TEST( testInPort_UnAttach_WithGeneralTemplateInPort_WhenIsNotAttached ); // todo: remove these Audio specific tests if the Audio template specialization is // no longer necessary (VC6 issue) CPPUNIT_TEST( testInPort_Attach_WithAudioInPort_UpdatesConcretePortState ); CPPUNIT_TEST( testInPort_Attach_WithAudioInPort_BadTypeAssertionFails ); CPPUNIT_TEST( testInPort_IsAttached_WithAudioInPort_AfterConstruction ); CPPUNIT_TEST( testInPort_IsAttached_WithAudioInPort_AfterAttach ); CPPUNIT_TEST( testInPort_IsAttached_WithAudioInPort_AfterUnattach ); CPPUNIT_TEST( testInPort_UnAttach_WithAudioInPort_WhenIsNotAttached ); // end todo //OutPorts CPPUNIT_TEST( testOutPort_Attach_WithGeneralTemplateOutPort_UpdatesConcretePortState ); CPPUNIT_TEST( testOutPort_Attach_WithGeneralTemplateOutPort_BadTypeAssertionFails ); CPPUNIT_TEST( testOutPort_IsAttached_WithGeneralTemplateOutPort_AfterConstruction ); CPPUNIT_TEST( testOutPort_IsAttached_WithGeneralTemplateOutPort_AfterAttach ); CPPUNIT_TEST( testOutPort_IsAttached_WithGeneralTemplateOutPort_AfterUnattach ); CPPUNIT_TEST( testOutPort_UnAttach_WithGeneralTemplateOutPort_WhenIsNotAttached ); // todo: remove these Audio specific tests if the Audio template specialization is // no longer necessary (VC6 issue) CPPUNIT_TEST( testOutPort_Attach_WithAudioOutPort_UpdatesConcretePortState ); CPPUNIT_TEST( testOutPort_Attach_WithAudioOutPort_BadTypeAssertionFails ); CPPUNIT_TEST( testOutPort_IsAttached_WithAudioOutPort_AfterConstruction ); CPPUNIT_TEST( testOutPort_IsAttached_WithAudioOutPort_AfterAttach ); CPPUNIT_TEST( testOutPort_IsAttached_WithAudioOutPort_AfterUnattach ); CPPUNIT_TEST( testOutPort_UnAttach_WithAudioOutPort_WhenIsNotAttached ); // end todo // testing of GetProcessingData methods CPPUNIT_TEST( testPort_GetProcessingData_WithAudioPort_AfterAttach ); CPPUNIT_TEST( testPort_GetProcessingData_WithGeneralTemplatePort_AfterAttach ); CPPUNIT_TEST( testPort_GetProcessingData_WithAudioPort_AfterConstruction ); CPPUNIT_TEST( testPort_GetProcessingData_WithGeneralTemplatePort_AfterConstruction ); // Testing of AreConnected() method CPPUNIT_TEST( testOutPort_IsConnectedTo_WithAudioPorts_WhenPortsAreConnected ); CPPUNIT_TEST( testOutPort_IsConnectedTo_WithGeneralTemplatePorts_WhenPortsAreConnected ); CPPUNIT_TEST( testOutPort_IsConnectedTo_WithAudioPorts_WhenPortsAreNotConnected ); CPPUNIT_TEST( testOutPort_IsConnectedTo_WithGeneralTemplatePorts_WhenPortsAreNotConnected ); CPPUNIT_TEST( testInPort_IsConnectedTo_DelegatesToOutPort ); // Testing OutPort interface CPPUNIT_TEST( testOutPort_IsConnectableTo_WithAudioOutPort_WhenInPortIsTheSameType ); CPPUNIT_TEST( testOutPort_IsConnectableTo_WithGeneralTemplate_WhenInPortIsTheSameType ); CPPUNIT_TEST( testOutPort_IsConnectableTo_WithAudioOutPort_WhenInPortIsDifferentType ); CPPUNIT_TEST( testOutPort_IsConnectableTo_WithGeneralTemplate_WhenInPortIsDifferentType ); // Tests for the concrete Port classes CPPUNIT_TEST_SUITE_END(); // Testing pattern: Self Shunt // Processing interface: const char* GetClassName() const { return "for testing"; } bool Do() { return false; } const CLAM::ProcessingConfig& GetConfig() const { throw 0; } bool ConcreteConfigure( const CLAM::ProcessingConfig& ) { return false; } ///////////////// TESTING IN PORTS ///////////////// void testInPort_Attach_WithGeneralTemplateInPort_UpdatesConcretePortState() { CLAM::InPort concreteInPort("in-port", this); DummyProcessingData attachedData; attachedData.SetState(1); CLAM::InPort &baseInPort = concreteInPort; baseInPort.Attach( attachedData ); CPPUNIT_ASSERT_EQUAL( concreteInPort.GetData().GetState(), attachedData.GetState() ); } void testInPort_Attach_WithAudioInPort_UpdatesConcretePortState() { CLAM::InPort concreteInPort("in-port", this); CLAM::Audio attachedAudio; CLAM::InPort &baseInPort = concreteInPort; baseInPort.Attach( attachedAudio ); // compare by reference (pointer) because Audio haven't yet operator== CPPUNIT_ASSERT_EQUAL( &concreteInPort.GetData(), &attachedAudio ); } void testInPort_Attach_WithGeneralTemplateInPort_BadTypeAssertionFails() { CLAM::InPort concreteInPort("in-port", this); CLAM::InPort &baseInPort = concreteInPort; CLAM::Audio attachedAudio; try { baseInPort.Attach( attachedAudio ); CPPUNIT_FAIL("assertion failed expected, but nothing happened"); } catch(CLAM::ErrAssertionFailed& ) {} } void testInPort_Attach_WithAudioInPort_BadTypeAssertionFails() { CLAM::InPort concreteInPort("in-port", this); CLAM::InPort &baseInPort = concreteInPort; DummyProcessingData attachedDummy; try { baseInPort.Attach( attachedDummy ); CPPUNIT_FAIL("assertion failed expected, but nothing happened"); } catch(CLAM::ErrAssertionFailed& ) {} } void testInPort_IsAttached_WithAudioInPort_AfterConstruction() { CLAM::InPort concreteInPort("in-port", this); CLAM::InPort &baseInPort = concreteInPort; CPPUNIT_ASSERT_EQUAL( false, baseInPort.IsAttached() ); } void testInPort_IsAttached_WithGeneralTemplateInPort_AfterConstruction() { CLAM::InPort concreteInPort("in-port", this); CLAM::InPort &baseInPort = concreteInPort; CPPUNIT_ASSERT_EQUAL( false, baseInPort.IsAttached() ); } void testInPort_IsAttached_WithGeneralTemplateInPort_AfterAttach() { CLAM::InPort concreteInPort("in-port", this); DummyProcessingData attached; CLAM::InPort &baseInPort = concreteInPort; baseInPort.Attach( attached ); CPPUNIT_ASSERT_EQUAL( true, concreteInPort.IsAttached() ); } void testInPort_IsAttached_WithAudioInPort_AfterAttach() { CLAM::InPort concreteInPort("in-port", this); CLAM::Audio attached; CLAM::InPort &baseInPort = concreteInPort; baseInPort.Attach( attached ); CPPUNIT_ASSERT_EQUAL( true, baseInPort.IsAttached() ); } void testInPort_IsAttached_WithAudioInPort_AfterUnattach() { CLAM::InPort concreteInPort("in-port", this); CLAM::Audio attached; CLAM::InPort &baseInPort = concreteInPort; baseInPort.Attach( attached ); baseInPort.Unattach(); CPPUNIT_ASSERT_EQUAL( false, baseInPort.IsAttached() ); } void testInPort_IsAttached_WithGeneralTemplateInPort_AfterUnattach() { CLAM::InPort concreteInPort("in-port", this); DummyProcessingData attached; CLAM::InPort &baseInPort = concreteInPort; baseInPort.Attach( attached ); baseInPort.Unattach(); CPPUNIT_ASSERT_EQUAL( false, baseInPort.IsAttached() ); } void testInPort_UnAttach_WithAudioInPort_WhenIsNotAttached() { CLAM::InPort concreteInPort("in-port", this); CLAM::InPort &baseInPort = concreteInPort; baseInPort.Unattach(); CPPUNIT_ASSERT_EQUAL( false, baseInPort.IsAttached() ); } void testInPort_UnAttach_WithGeneralTemplateInPort_WhenIsNotAttached() { CLAM::InPort concreteInPort("in-port", this); CLAM::InPort &baseInPort = concreteInPort; baseInPort.Unattach(); CPPUNIT_ASSERT_EQUAL( false, baseInPort.IsAttached() ); } ///////////////// TESTING OUT PORTS ///////////////// void testOutPort_Attach_WithGeneralTemplateOutPort_UpdatesConcretePortState() { CLAM::OutPort concreteOutPort("out-port", this); DummyProcessingData attachedData; attachedData.SetState(1); CLAM::OutPort &baseOutPort = concreteOutPort; baseOutPort.Attach( attachedData ); CPPUNIT_ASSERT_EQUAL( concreteOutPort.GetData().GetState(), attachedData.GetState() ); } void testOutPort_Attach_WithAudioOutPort_UpdatesConcretePortState() { CLAM::OutPort concreteOutPort("out-port", this); CLAM::Audio attachedAudio; CLAM::OutPort &baseOutPort = concreteOutPort; baseOutPort.Attach( attachedAudio ); // compare by reference (pointer) because Audio haven't yet operator== CPPUNIT_ASSERT_EQUAL( &concreteOutPort.GetData(), &attachedAudio ); } void testOutPort_Attach_WithGeneralTemplateOutPort_BadTypeAssertionFails() { CLAM::OutPort concreteOutPort("out-port", this); CLAM::OutPort &baseOutPort = concreteOutPort; CLAM::Audio attachedAudio; try { baseOutPort.Attach( attachedAudio ); CPPUNIT_FAIL("assertion failed expected, but nothing happened"); } catch(CLAM::ErrAssertionFailed& ) {} } void testOutPort_Attach_WithAudioOutPort_BadTypeAssertionFails() { CLAM::OutPort &baseOutPort = concreteOutPort; DummyProcessingData attachedDummy; try { baseOutPort.Attach( attachedDummy ); CPPUNIT_FAIL("assertion failed expected, but nothing happened"); } catch(CLAM::ErrAssertionFailed& ) {} } void testOutPort_IsAttached_WithAudioOutPort_AfterConstruction() { CLAM::OutPort concreteOutPort("out-port", this); CLAM::OutPort &baseOutPort = concreteOutPort; CPPUNIT_ASSERT_EQUAL( false, baseOutPort.IsAttached() ); } void testOutPort_IsAttached_WithGeneralTemplateOutPort_AfterConstruction() { CLAM::OutPort concreteOutPort("out-port", this); CLAM::OutPort &baseOutPort = concreteOutPort; CPPUNIT_ASSERT_EQUAL( false, baseOutPort.IsAttached() ); } void testOutPort_IsAttached_WithGeneralTemplateOutPort_AfterAttach() { CLAM::OutPort concreteOutPort("out-port", this); DummyProcessingData attached; CLAM::OutPort &baseOutPort = concreteOutPort; baseOutPort.Attach( attached ); CPPUNIT_ASSERT_EQUAL( true, concreteOutPort.IsAttached() ); } void testOutPort_IsAttached_WithAudioOutPort_AfterAttach() { CLAM::OutPort concreteOutPort("out-port", this); CLAM::Audio attached; CLAM::OutPort &baseOutPort = concreteOutPort; baseOutPort.Attach( attached ); CPPUNIT_ASSERT_EQUAL( true, baseOutPort.IsAttached() ); } void testOutPort_IsAttached_WithAudioOutPort_AfterUnattach() { CLAM::OutPort concreteOutPort("out-port", this); CLAM::Audio attached; CLAM::OutPort &baseOutPort = concreteOutPort; baseOutPort.Attach( attached ); baseOutPort.Unattach(); CPPUNIT_ASSERT_EQUAL( false, baseOutPort.IsAttached() ); } void testOutPort_IsAttached_WithGeneralTemplateOutPort_AfterUnattach() { const int dummyLength = 0; CLAM::OutPort concreteOutPort("out-port", this); DummyProcessingData attached; CLAM::OutPort &baseOutPort = concreteOutPort; baseOutPort.Attach( attached ); baseOutPort.Unattach(); CPPUNIT_ASSERT_EQUAL( false, baseOutPort.IsAttached() ); } void testOutPort_UnAttach_WithAudioOutPort_WhenIsNotAttached() { const int dummyLength = 0; CLAM::OutPort concreteOutPort("out-port", this); CLAM::OutPort &baseOutPort = concreteOutPort; baseOutPort.Unattach(); CPPUNIT_ASSERT_EQUAL( false, baseOutPort.IsAttached() ); } void testOutPort_UnAttach_WithGeneralTemplateOutPort_WhenIsNotAttached() { const int dummyLength = 0; CLAM::OutPort concreteOutPort("out-port", this); CLAM::OutPort &baseOutPort = concreteOutPort; baseOutPort.Unattach(); CPPUNIT_ASSERT_EQUAL( false, baseOutPort.IsAttached() ); } ////////// GetProcessingData testing /////// void testPort_GetProcessingData_WithAudioPort_AfterAttach() { const int dummyLength = 0; CLAM::InPort concreteInPort("in-port", this); CLAM::Port &basePort = concreteInPort; CLAM::Audio attached; concreteInPort.Attach( attached ); basePort.GetProcessingData(); CPPUNIT_ASSERT_EQUAL( (CLAM::ProcessingData*)&attached, basePort.GetProcessingData() ); } void testPort_GetProcessingData_WithGeneralTemplatePort_AfterAttach() { const int dummyLength = 0; CLAM::InPort concreteInPort("in-port", this); CLAM::Port &basePort = concreteInPort; DummyProcessingData attached; concreteInPort.Attach( attached ); CPPUNIT_ASSERT_EQUAL( (CLAM::ProcessingData*)&attached, basePort.GetProcessingData() ); } void testPort_GetProcessingData_WithAudioPort_AfterConstruction() { const int dummyLength = 0; CLAM::InPort concreteInPort("in-port", this); CLAM::Port &basePort = concreteInPort; CLAM::ProcessingData* p = 0; CPPUNIT_ASSERT_EQUAL( p , basePort.GetProcessingData() ); } void testPort_GetProcessingData_WithGeneralTemplatePort_AfterConstruction() { const int dummyLength = 0; CLAM::InPort concreteInPort("in-port", this); CLAM::Port &basePort = concreteInPort; CLAM::ProcessingData* p = 0; CPPUNIT_ASSERT_EQUAL( p , basePort.GetProcessingData() ); } //////////// Connectability testing ////////////// void testOutPort_IsConnectedTo_WithAudioPorts_WhenPortsAreConnected() { const int dummyLength = 0; CLAM::InPort concreteInPort("in-port", this); CLAM::InPort &baseInPort = concreteInPort; CLAM::OutPort concreteOutPort("out-port", this); CLAM::OutPort &baseOutPort = concreteOutPort; CLAM::Audio attached; baseInPort.Attach( attached ); baseOutPort.Attach( attached ); CPPUNIT_ASSERT_EQUAL( true, baseOutPort.IsConnectedTo( baseInPort ) ); } void testOutPort_IsConnectedTo_WithGeneralTemplatePorts_WhenPortsAreConnected() { const int dummyLength = 0; CLAM::InPort concreteInPort("in-port", this); CLAM::InPort &baseInPort = concreteInPort; CLAM::OutPort concreteOutPort("out-port", this); CLAM::OutPort &baseOutPort = concreteOutPort; DummyProcessingData attached; baseInPort.Attach( attached ); baseOutPort.Attach( attached ); CPPUNIT_ASSERT_EQUAL( true, baseInPort.IsConnectedTo(baseOutPort) ); } void testOutPort_IsConnectedTo_WithAudioPorts_WhenPortsAreNotConnected() { const int dummyLength = 0; CLAM::InPort concreteInPort("in-port", this); CLAM::InPort &baseInPort = concreteInPort; CLAM::OutPort concreteOutPort("out-port", this); CLAM::OutPort &baseOutPort = concreteOutPort; CPPUNIT_ASSERT_EQUAL( false, baseInPort.IsConnectedTo(baseOutPort) ); } void testInPort_IsConnectedTo_DelegatesToOutPort() { const int dummyLength = 0; CLAM::InPort concreteInPort("in-port", this); CLAM::InPort &baseInPort = concreteInPort; CLAM::OutPort concreteOutPort("out-port", this); CLAM::OutPort &baseOutPort = concreteOutPort; CPPUNIT_ASSERT_EQUAL( false, baseInPort.IsConnectedTo(baseOutPort) ); } void testOutPort_IsConnectedTo_WithGeneralTemplatePorts_WhenPortsAreNotConnected() { const int dummyLength = 0; CLAM::InPort concreteInPort("in-port", this); CLAM::InPort &baseInPort = concreteInPort; CLAM::OutPort concreteOutPort("out-port", this); CLAM::OutPort &baseOutPort = concreteOutPort; CPPUNIT_ASSERT_EQUAL( false, baseInPort.IsConnectedTo(baseOutPort) ); } void testOutPort_IsConnectableTo_WithAudioOutPort_WhenInPortIsTheSameType() { const int dummyLength = 0; CLAM::OutPort out("out-port", this ); CLAM::InPort in("in-port", this ); CLAM::OutPort & baseOutPort = out; CLAM::InPort & baseInPort = in; CPPUNIT_ASSERT_EQUAL( true, baseOutPort.IsConnectableTo(baseInPort) ); } void testOutPort_IsConnectableTo_WithGeneralTemplate_WhenInPortIsTheSameType() { const int dummyLength = 0; CLAM::OutPort out("out-port", this ); CLAM::InPort in("in-port", this ); CLAM::OutPort & baseOutPort = out; CLAM::InPort & baseInPort = in; CPPUNIT_ASSERT_EQUAL( true, baseOutPort.IsConnectableTo(baseInPort) ); } void testOutPort_IsConnectableTo_WithAudioOutPort_WhenInPortIsDifferentType() { const int dummyLength = 0; CLAM::OutPort out("out-port", this ); CLAM::InPort in("in-port", this ); CLAM::OutPort & baseOutPort = out; CLAM::InPort & baseInPort = in; CPPUNIT_ASSERT_EQUAL( false, baseOutPort.IsConnectableTo(baseInPort) ); } void testOutPort_IsConnectableTo_WithGeneralTemplate_WhenInPortIsDifferentType() { const int dummyLength = 0; CLAM::OutPort out("out-port", this ); CLAM::InPort in("in-port", this ); CLAM::OutPort & baseOutPort = out; CLAM::InPort & baseInPort = in; CPPUNIT_ASSERT_EQUAL( false, baseOutPort.IsConnectableTo(baseInPort) ); } }; } //namespace clam-1.4.0/test/UnitTests/TestRunnerQt.cxx0000644000000000000000000000201311212224663017204 0ustar rootroot#include #include #include #include #include #include "cppUnitHelper.hxx" #include "Assert.hxx" int main(int argc, char ** argv){ // this flag allows clam asserts to behave throwing an exception instead // of doing breakpoint. Thus making auto-testing of asserts possible. // Notice: while debugging tests (if breakpoints are wanted back) you might need to // modify this flag before the point to be debugged. CLAM::ErrAssertionFailed::breakpointInCLAMAssertEnabled = false; QApplication application(argc, argv); CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry(); CppUnit::Test* theTest = registry.makeTest(); CLAMTest::Helper::printTestNames( theTest ); // The other way of running a test suite: using TestRunner. CppUnit::QtUi::TestRunner runner; runner.addTest( theTest ); // caution: it deletes the suite on termination. runner.run(""); return 0; } clam-1.4.0/test/UnitTests/ProcessingDataTests/0000755000000000000000000000000011344231437020002 5ustar rootrootclam-1.4.0/test/UnitTests/ProcessingDataTests/SpectrumConversionsTest.cxx0000644000000000000000000001135610610720021025412 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "Spectrum.hxx" // CLAM #include "SpecTypeFlags.hxx" // CLAM #include "SpectrumConfig.hxx" // CLAM namespace CLAMTest { class SpectrumConversionsTest; CPPUNIT_TEST_SUITE_REGISTRATION( SpectrumConversionsTest ); class SpectrumConversionsTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( SpectrumConversionsTest ); CPPUNIT_TEST( testDefaultSpectrum ); CPPUNIT_TEST( testMagPhase2BPF2MagPhase ); CPPUNIT_TEST( testComplex2BPF2Complex ); CPPUNIT_TEST( testComplex2BPF2ComplexWithDifferentSpectrums ); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: void testDefaultSpectrum() { CLAM::Spectrum spec; CPPUNIT_ASSERT( CLAM::TData(22050) == spec.GetSpectralRange() ); CPPUNIT_ASSERT( 0 == spec.GetSize() ); CPPUNIT_ASSERT( 0 == spec.GetBPFSize() ); CLAM::SpecTypeFlags typeFlags; spec.GetType( typeFlags ); CPPUNIT_ASSERT( true == typeFlags.bMagPhase ); CPPUNIT_ASSERT( false == typeFlags.bComplex ); CPPUNIT_ASSERT( false == typeFlags.bPolar ); CPPUNIT_ASSERT( false == typeFlags.bMagPhaseBPF ); } void testMagPhase2BPF2MagPhase() { CLAM::Spectrum spec; CLAM::SpectrumConfig config; config.SetSize(22050); spec.Configure(config); CLAM::DataArray & mag = spec.GetMagBuffer(); CLAM::DataArray & phase = spec.GetPhaseBuffer(); for(int i=0; i<22050; i++) { mag[i] = CLAM::TData(0.1); phase[i] = CLAM::TData(-0.1); } CLAM::SpecTypeFlags bpfAndMagphaseFlag; bpfAndMagphaseFlag.bMagPhaseBPF = true; bpfAndMagphaseFlag.bMagPhase=false; spec.SetTypeSynchronize(bpfAndMagphaseFlag); CLAM::SpecTypeFlags magphaseFlag; CPPUNIT_ASSERT_EQUAL(22050, spec.GetBPFSize() ); CLAM::BPF & magBpf = spec.GetMagBPF(); CLAM::BPF & phaseBpf = spec.GetPhaseBPF(); for(int i=0; i<22050; i++) { CPPUNIT_ASSERT( CLAM::TData(0.1) == magBpf.GetValue(i) ); CPPUNIT_ASSERT( CLAM::TData(-0.1) == phaseBpf.GetValue(i) ); } spec.SetTypeSynchronize(magphaseFlag); for(int i=0; i<22050; i++) { CPPUNIT_ASSERT( mag[i] == CLAM::TData(0.1)); CPPUNIT_ASSERT( phase[i] == CLAM::TData(-0.1)); } } void testComplex2BPF2Complex() { CLAM::Spectrum spec; CLAM::SpectrumConfig config; config.SetSize(22050); CLAM::SpecTypeFlags complexFlag; complexFlag.bMagPhase=false; complexFlag.bComplex=true; config.SetType(complexFlag); spec.Configure(config); CLAM::Array & complexArray = spec.GetComplexArray(); for(int i=0; i<22050; i++) { complexArray[i].SetReal(CLAM::TData(1)); complexArray[i].SetImag(CLAM::TData(0)); } CLAM::SpecTypeFlags bpfFlag; bpfFlag.bMagPhase=false; bpfFlag.bMagPhaseBPF = true; spec.SetTypeSynchronize(bpfFlag); CPPUNIT_ASSERT_EQUAL(22050, spec.GetBPFSize() ); CLAM::BPF & magBpf = spec.GetMagBPF(); CLAM::BPF & phaseBpf = spec.GetPhaseBPF(); for(int i=0; i<22050; i++) { CPPUNIT_ASSERT( CLAM::TData(1) == magBpf.GetValue(i) ); CPPUNIT_ASSERT( CLAM::TData(0) == phaseBpf.GetValue(i) ); } spec.SetTypeSynchronize(complexFlag); for(int i=0; i<22050; i++) { CPPUNIT_ASSERT( complexArray[i].Real() == CLAM::TData(1)); CPPUNIT_ASSERT( complexArray[i].Imag() == CLAM::TData(0)); } } void testComplex2BPF2ComplexWithDifferentSpectrums() { CLAM::Spectrum complexSpec; CLAM::SpectrumConfig config; config.SetSize(22050); CLAM::SpecTypeFlags complexFlag; complexFlag.bMagPhase=false; complexFlag.bComplex=true; config.SetType(complexFlag); complexSpec.Configure(config); CLAM::Spectrum BPFSpec; CLAM::SpectrumConfig config2; config2.SetSize(22050); CLAM::SpecTypeFlags bpfFlag; bpfFlag.bMagPhase=false; bpfFlag.bMagPhaseBPF=true; config2.SetType(bpfFlag); BPFSpec.Configure(config2); CLAM::Array & complexArray = complexSpec.GetComplexArray(); for(int i=0; i<22050; i++) { complexArray[i].SetReal(CLAM::TData(1)); complexArray[i].SetImag(CLAM::TData(0)); } BPFSpec.SynchronizeTo(complexSpec); CPPUNIT_ASSERT_EQUAL(22050, BPFSpec.GetBPFSize() ); CLAM::BPF & magBpf = BPFSpec.GetMagBPF(); CLAM::BPF & phaseBpf = BPFSpec.GetPhaseBPF(); for(int i=0; i<22050; i++) { CPPUNIT_ASSERT( CLAM::TData(1) == magBpf.GetValue(i) ); CPPUNIT_ASSERT( CLAM::TData(0) == phaseBpf.GetValue(i) ); } complexSpec.SynchronizeTo(BPFSpec); for(int i=0; i<22050; i++) { CPPUNIT_ASSERT( complexArray[i].Real() == CLAM::TData(1)); CPPUNIT_ASSERT( complexArray[i].Imag() == CLAM::TData(0)); } } void testMagPhase2Complex2MagPhase() { } void testMagPhase2Polar2MagPhase() { } void testPolar2Complex2Polar() { } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/ProcessingDataTests/AudioTest.cxx0000644000000000000000000000335411323652563022440 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "Audio.hxx" // CLAM #include "Array.hxx" // CLAM namespace CLAMTest { class AudioTest; CPPUNIT_TEST_SUITE_REGISTRATION( AudioTest ); class AudioTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( AudioTest ); CPPUNIT_TEST(testAudioInit_byDefault); CPPUNIT_TEST(testSetSize_reallocates); CPPUNIT_TEST(testResizeAudio_increasingSize); CPPUNIT_TEST(testResizeAudio_reducingSizeDoesNotReallocate); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: void testAudioInit_byDefault() { CLAM::Audio prueba; CPPUNIT_ASSERT_EQUAL( 0, prueba.GetSize()); CPPUNIT_ASSERT_EQUAL( 44100.0f, prueba.GetSampleRate() ); CPPUNIT_ASSERT_EQUAL( 0., prueba.GetBeginTime() ); } void testSetSize_reallocates() { CLAM::Audio prueba; prueba.SetSize(4); CPPUNIT_ASSERT_EQUAL( 4, prueba.GetSize() ); CPPUNIT_ASSERT_EQUAL( 4, prueba.GetBuffer().Size() ); CPPUNIT_ASSERT_EQUAL( 4, prueba.GetBuffer().AllocatedSize() ); } void testResizeAudio_increasingSize() { CLAM::Audio prueba; prueba.SetSize(4); prueba.SetSize(5); CPPUNIT_ASSERT_EQUAL( 5, prueba.GetSize() ); CPPUNIT_ASSERT_EQUAL( 5, prueba.GetBuffer().Size() ); CPPUNIT_ASSERT_EQUAL( 5, prueba.GetBuffer().AllocatedSize() ); } void testResizeAudio_reducingSizeDoesNotReallocate() { CLAM::Audio prueba; prueba.SetSize(4); prueba.SetSize(3); CPPUNIT_ASSERT_EQUAL( 3, prueba.GetSize()); CPPUNIT_ASSERT_EQUAL( 3, prueba.GetBuffer().Size()); CPPUNIT_ASSERT_EQUAL( 4, prueba.GetBuffer().AllocatedSize()); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/XmlTests/0000755000000000000000000000000011344231436015633 5ustar rootrootclam-1.4.0/test/UnitTests/XmlTests/XmlMockUpObjectsTest.cxx0000644000000000000000000001071210441623077022414 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "XmlMockUpObjects.hxx" namespace CLAM { namespace Test { class XmlMockUpObjectsTest; CPPUNIT_TEST_SUITE_REGISTRATION( XmlMockUpObjectsTest ); class XmlMockUpObjectsTest : public CppUnit::TestCase { CPPUNIT_TEST_SUITE( XmlMockUpObjectsTest ); CPPUNIT_TEST(testTraceStructure_basicWithoutLevelAndContent); CPPUNIT_TEST(testTraceStructure_basicWithContent); CPPUNIT_TEST(testTraceStructure_basicWithLevel); CPPUNIT_TEST(testTraceStructure_emptyComponent); CPPUNIT_TEST(testTraceStructure_emptyComponentWithLevel); CPPUNIT_TEST(testTraceStructure_componentWithBasicsInside); CPPUNIT_TEST(testTraceStructure_componentWithComponentsInside); CPPUNIT_TEST(testXMLContentSetter_whenOneWord); CPPUNIT_TEST(testXMLContentSetter_whenTwoWords); CPPUNIT_TEST(testXMLContentSetter_whenNoWordsGivesDefaultValue); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: std::stringstream mTargetStream; void testTraceStructure_basicWithoutLevelAndContent() { XmlMockUpBasic basic; std::string expected="B''\n"; CPPUNIT_ASSERT_EQUAL(expected, basic.structureTrace(0)); } void testTraceStructure_basicWithContent() { XmlMockUpBasic basic; basic.setContent("Content"); std::string expected="B'Content'\n"; CPPUNIT_ASSERT_EQUAL(expected, basic.structureTrace(0)); } void testTraceStructure_basicWithLevel() { XmlMockUpBasic basic; basic.setContent("Content"); std::string expected="..B'Content'\n"; CPPUNIT_ASSERT_EQUAL(expected, basic.structureTrace(2)); } void testTraceStructure_emptyComponent() { XmlMockUpComponent component; component.setContent("Content"); std::string expected= "C'Content'\n" "{\n" "}\n"; CPPUNIT_ASSERT_EQUAL(expected, component.structureTrace(0)); } void testTraceStructure_emptyComponentWithLevel() { XmlMockUpComponent component; component.setContent("Content"); std::string expected= "..C'Content'\n" "..{\n" "..}\n"; CPPUNIT_ASSERT_EQUAL(expected, component.structureTrace(2)); } void testTraceStructure_componentWithBasicsInside() { XmlMockUpComponent component; component.setContent("ComponentContent"); XmlMockUpBasic basic1; basic1.setContent("Basic1Content"); component.add(basic1); XmlMockUpBasic basic2; basic2.setContent("Basic2Content"); component.add(basic2); std::string expected= "C'ComponentContent'\n" "{\n" ".B'Basic1Content'\n" ".B'Basic2Content'\n" "}\n"; CPPUNIT_ASSERT_EQUAL(expected, component.structureTrace(0)); } void testTraceStructure_componentWithComponentsInside() { XmlMockUpComponent component; XmlMockUpComponent innerComponent; XmlMockUpBasic basic1; XmlMockUpBasic basic2; component.setContent("ComponentContent"); innerComponent.setContent("InnerComponentContent"); basic1.setContent("Basic1Content"); basic2.setContent("Basic2Content"); component.add(innerComponent); innerComponent.add(basic1); innerComponent.add(basic2); std::string expected= "C'ComponentContent'\n" "{\n" ".C'InnerComponentContent'\n" ".{\n" "..B'Basic1Content'\n" "..B'Basic2Content'\n" ".}\n" "}\n"; CPPUNIT_ASSERT_EQUAL(expected, component.structureTrace(0)); } void testXMLContentSetter_whenOneWord() { XmlMockUpBasic basic; basic.setContent("PreviousContent"); std::istringstream is("NewContent"); std::string expected="B'NewContent'\n"; bool result = basic.XMLContent(is); CPPUNIT_ASSERT_MESSAGE("XMLContent should have succeded", result); CPPUNIT_ASSERT_EQUAL(expected, basic.structureTrace(0)); } void testXMLContentSetter_whenTwoWords() { XmlMockUpBasic basic; basic.setContent("PreviousContent"); std::istringstream is("NewContent AdditionalContent"); std::string expected="B'NewContent'\n"; bool result = basic.XMLContent(is); CPPUNIT_ASSERT_MESSAGE("XMLContent should have succeded", result); CPPUNIT_ASSERT_EQUAL(expected, basic.structureTrace(0)); } void testXMLContentSetter_whenNoWordsGivesDefaultValue() { XmlMockUpBasic basic; basic.setContent("PreviousContent"); std::istringstream is(""); std::string expected="B''\n"; bool result = basic.XMLContent(is); CPPUNIT_ASSERT_MESSAGE("XMLContent should have failed", !result); CPPUNIT_ASSERT_EQUAL(expected, basic.structureTrace(0)); } }; } // namespace Test } // namespace Cuidado clam-1.4.0/test/UnitTests/XmlTests/XercesDomWriterTest.cxx0000644000000000000000000001614711037400122022303 0ustar rootroot#ifdef USE_XERCES #include #include "cppUnitHelper.hxx" #include "XercesDomWriter.hxx" // CLAM #include "XercesInitializer.hxx" // CLAM #include "XercesEncodings.hxx" // CLAM #include #include #include #include #include namespace CLAM { namespace Test { class XercesDomWriterTest; CPPUNIT_TEST_SUITE_REGISTRATION( XercesDomWriterTest ); class XercesDomWriterTest : public CppUnit::TestCase { CPPUNIT_TEST_SUITE( XercesDomWriterTest ); CPPUNIT_TEST(testPlainContent); CPPUNIT_TEST(testEmptyElement); CPPUNIT_TEST(testElementWithPlainContent); CPPUNIT_TEST(testElementWithInnerElement); CPPUNIT_TEST(testEmptyElementWithAttribute); CPPUNIT_TEST(testEmptyElementWithAttributes); CPPUNIT_TEST(testEmptyElementWithReversedOrderAttributes); CPPUNIT_TEST(testNonEmptyElementWithAttribute); CPPUNIT_TEST(testEmptyDocument); CPPUNIT_TEST(testDocumentWithFullContent); CPPUNIT_TEST(testDocumentWithFullContentAndIndentation); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { XercesInitializer::require(); mTargetStream.str(""); xercesc::DOMImplementation * imp = xercesc::DOMImplementation::getImplementation(); mDocument = imp->createDocument( U("2003-04.clam05.iua.mtg.upf.es"), // root element namespace URI. U("TestDoc"), // root element name 0 // document type object (DTD). ); } /// Common clean up, executed after each test method void tearDown() { mDocument->release(); } private: std::stringstream mTargetStream; xercesc::DOMDocument * mDocument; void testPlainContent() { xercesc::DOMText * domContent = mDocument->createTextNode(U("Content")); XercesDomWriter writer; writer.write(mTargetStream, domContent); CPPUNIT_ASSERT_EQUAL(std::string("Content"), mTargetStream.str()); domContent->release(); } void testEmptyElement() { xercesc::DOMElement * domElement = mDocument->createElement(U("EmptyElement")); XercesDomWriter writer; writer.write(mTargetStream, domElement); CPPUNIT_ASSERT_EQUAL(std::string(""), mTargetStream.str()); } void testElementWithPlainContent() { xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); xercesc::DOMText * domContent = mDocument->createTextNode(U("Content")); domElement->appendChild(domContent); XercesDomWriter writer; writer.write(mTargetStream, domElement); CPPUNIT_ASSERT_EQUAL(std::string("Content"), mTargetStream.str()); } void testElementWithInnerElement() { xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); xercesc::DOMElement * domInnerElement = mDocument->createElement(U("InnerElement")); xercesc::DOMText * domContent = mDocument->createTextNode(U("Content")); domInnerElement->appendChild(domContent); domElement->appendChild(domInnerElement); XercesDomWriter writer; writer.write(mTargetStream, domElement); CPPUNIT_ASSERT_EQUAL(std::string("Content"), mTargetStream.str()); } void testEmptyElementWithAttribute() { xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); domElement->setAttribute(U("attribute"),U("Attribute value")); XercesDomWriter writer; writer.write(mTargetStream, domElement); CPPUNIT_ASSERT_EQUAL(std::string(""), mTargetStream.str()); } void testEmptyElementWithAttributes() { xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); domElement->setAttribute(U("attribute1"),U("Attribute 1 value")); domElement->setAttribute(U("attribute2"),U("Attribute 2 value")); XercesDomWriter writer; writer.write(mTargetStream, domElement); CPPUNIT_ASSERT_EQUAL(std::string(""), mTargetStream.str()); } void testEmptyElementWithReversedOrderAttributes() { xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); domElement->setAttribute(U("attribute2"),U("Attribute 2 value")); domElement->setAttribute(U("attribute1"),U("Attribute 1 value")); XercesDomWriter writer; writer.write(mTargetStream, domElement); CPPUNIT_ASSERT_EQUAL(std::string(""), mTargetStream.str()); } void testNonEmptyElementWithAttribute() { xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); xercesc::DOMElement * domInnerElement = mDocument->createElement(U("InnerElement")); domElement->setAttribute(U("attribute"),U("Attribute value")); domElement->appendChild(domInnerElement); XercesDomWriter writer; writer.write(mTargetStream, domElement); CPPUNIT_ASSERT_EQUAL(std::string(""), mTargetStream.str()); } void testEmptyDocument() { XercesDomWriter writer; writer.write(mTargetStream, mDocument); CPPUNIT_ASSERT_EQUAL(std::string( "" "" ), mTargetStream.str()); } void testDocumentWithFullContent() { xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); xercesc::DOMElement * domInnerElement = mDocument->createElement(U("InnerElement")); xercesc::DOMText * domContent = mDocument->createTextNode(U("Content")); domElement->setAttribute(U("attribute"),U("Attribute value")); domElement->appendChild(domContent); domElement->appendChild(domInnerElement); mDocument->getDocumentElement()->appendChild(domElement); XercesDomWriter writer; writer.write(mTargetStream, mDocument); CPPUNIT_ASSERT_EQUAL(std::string( "" "" "" "Content" "" "" "" ), mTargetStream.str()); } void testDocumentWithFullContentAndIndentation() { xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); xercesc::DOMElement * domInnerElement = mDocument->createElement(U("InnerElement")); xercesc::DOMText * domContent = mDocument->createTextNode(U("Content")); domElement->setAttribute(U("attribute"),U("Attribute value")); domElement->appendChild(domContent); domElement->appendChild(domInnerElement); mDocument->getDocumentElement()->appendChild(domElement); XercesDomWriter writer; writer.DoIndentedFormat(true); writer.write(mTargetStream, mDocument); // Xerces does a very weird indentation!! CPPUNIT_ASSERT_EQUAL(std::string( "\n" "\n\n" " " "Content\n" " \n" " \n\n" "\n" ), mTargetStream.str()); } }; } // namespace Test } // namespace Cuidado #endif // USE_XERCES clam-1.4.0/test/UnitTests/XmlTests/XmlWriteContextTest.cxx0000644000000000000000000003357110442000724022340 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "XmlWriteContext.hxx" // CLAM namespace CLAM { namespace Test { class XmlWriteContextTest; CPPUNIT_TEST_SUITE_REGISTRATION( XmlWriteContextTest ); class XmlWriteContextTest : public CppUnit::TestCase { CPPUNIT_TEST_SUITE( XmlWriteContextTest ); CPPUNIT_TEST( testCurrentContext_whenNoContextDefinedFails ); CPPUNIT_TEST( testConstructor_establishCurrentContext ); CPPUNIT_TEST( testDestructor_removesCurrentContext ); CPPUNIT_TEST( testConstructor_whenASecondContextDefinedFails ); CPPUNIT_TEST( testGetTarget ); CPPUNIT_TEST( testInsertContent_whenString ); CPPUNIT_TEST( testInsertContent_whenInteger ); CPPUNIT_TEST( testOpenElement ); CPPUNIT_TEST( testCloseElement_whenEmpty ); CPPUNIT_TEST( testCloseElement_whenHasContent ); CPPUNIT_TEST( testCloseElement_whenHasChildren ); CPPUNIT_TEST( testCloseElement_whenHasSiblings ); CPPUNIT_TEST( testLastWasAContent_whenConstructed ); CPPUNIT_TEST( testLastWasAContent_whenContentWasInserted ); CPPUNIT_TEST( testLastWasAContent_whenElementOpened ); CPPUNIT_TEST( testLastWasAContent_whenElementClosed ); CPPUNIT_TEST( testLastWasAContent_whenContentInsertedOnElement ); CPPUNIT_TEST( testLastWasAContent_whenElementWithContentClosed ); CPPUNIT_TEST( testInsertAttribute_whenOutsideTheTagFails ); CPPUNIT_TEST( testInsertAttribute_whenEmpty ); CPPUNIT_TEST( testInsertAttribute_whenFull ); CPPUNIT_TEST( testCurrentLevel_whenConstructed ); CPPUNIT_TEST( testCurrentLevel_whenContentAdded ); CPPUNIT_TEST( testCurrentLevel_whenElementOpened ); CPPUNIT_TEST( testCurrentLevel_whenTwoElementsOpened ); CPPUNIT_TEST( testCurrentLevel_whenOneElementClosed ); CPPUNIT_TEST( testCurrentLevel_whenTwoElementClosed ); CPPUNIT_TEST( testCurrentLevel_whenFirstOfTwoElementClosed ); CPPUNIT_TEST( testIndentation_whenSingleContent ); CPPUNIT_TEST( testIndentation_whenSingleElement ); CPPUNIT_TEST( testIndentation_whenRootSiblings ); CPPUNIT_TEST( testIndentation_whenNested ); CPPUNIT_TEST( testIndentation_whenNestedSiblings ); CPPUNIT_TEST( testIndentation_whenNestedSingleContent ); CPPUNIT_TEST( testIndentation_whenNestedPreContent ); CPPUNIT_TEST( testIndentation_whenNestedPostContent ); CPPUNIT_TEST( testIndentation_whenNestedNested ); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { mTargetStream.str(""); } /// Common clean up, executed after each test method void tearDown() { } private: std::stringstream mTargetStream; void testCurrentContext_whenNoContextDefinedFails() { try { XmlWriteContext::CurrentContext(); CPPUNIT_FAIL("Assertion should have failed"); } catch (CLAM::ErrAssertionFailed e) { CPPUNIT_ASSERT_EQUAL( std::string("XML generation context not created"), std::string(e.what())); } } void testConstructor_establishCurrentContext() { XmlWriteContext theContext(mTargetStream); CPPUNIT_ASSERT_EQUAL(&theContext, &XmlWriteContext::CurrentContext()); } void testDestructor_removesCurrentContext() { { XmlWriteContext theContext(mTargetStream); // Will be destroyed here } try { XmlWriteContext::CurrentContext(); CPPUNIT_FAIL("Assertion should have failed"); } catch (CLAM::ErrAssertionFailed e) { CPPUNIT_ASSERT_EQUAL( std::string("XML generation context not created"), std::string(e.what())); } } void testConstructor_whenASecondContextDefinedFails() { XmlWriteContext theContext(mTargetStream); try { XmlWriteContext banglerContext(mTargetStream); CPPUNIT_FAIL("Assertion should have failed"); } catch (CLAM::ErrAssertionFailed e) { CPPUNIT_ASSERT_EQUAL( std::string("An XML generation context is already defined"), std::string(e.what())); } } void testGetTarget() { XmlWriteContext theContext(mTargetStream); CPPUNIT_ASSERT_EQUAL_MESSAGE("mTargetStream is not the one GetTarget returned", static_cast(&mTargetStream), &theContext.GetTarget()); } void testLastWasAContent_whenConstructed() { XmlWriteContext theContext(mTargetStream); CPPUNIT_ASSERT_EQUAL(false,theContext.LastWasAContent()); } void testLastWasAContent_whenContentWasInserted() { XmlWriteContext theContext(mTargetStream); theContext.InsertContent(3); CPPUNIT_ASSERT_EQUAL(true,theContext.LastWasAContent()); } void testLastWasAContent_whenElementOpened() { XmlWriteContext theContext(mTargetStream); theContext.InsertContent("A dummy text"); theContext.OpenElement("MyElement"); CPPUNIT_ASSERT_EQUAL(false,theContext.LastWasAContent()); } void testLastWasAContent_whenElementClosed() { XmlWriteContext theContext(mTargetStream); theContext.InsertContent("A dummy text"); theContext.OpenElement("MyElement"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL(false,theContext.LastWasAContent()); } void testLastWasAContent_whenContentInsertedOnElement() { XmlWriteContext theContext(mTargetStream); theContext.OpenElement("MyElement"); theContext.InsertContent("A dummy text"); CPPUNIT_ASSERT_EQUAL(true,theContext.LastWasAContent()); } void testLastWasAContent_whenElementWithContentClosed() { XmlWriteContext theContext(mTargetStream); theContext.OpenElement("MyElement"); theContext.InsertContent("A dummy text"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL(false,theContext.LastWasAContent()); } void testInsertContent_whenInteger() { XmlWriteContext theContext(mTargetStream); theContext.InsertContent(3); CPPUNIT_ASSERT_EQUAL(std::string("3"), mTargetStream.str()); } void testInsertContent_whenString() { XmlWriteContext theContext(mTargetStream); theContext.InsertContent("A dummy text"); CPPUNIT_ASSERT_EQUAL(std::string("A dummy text"), mTargetStream.str()); } void testOpenElement() { XmlWriteContext theContext(mTargetStream); theContext.OpenElement("MyElement"); CPPUNIT_ASSERT_EQUAL(std::string(""), mTargetStream.str()); } void testCloseElement_whenHasContent() { XmlWriteContext theContext(mTargetStream); theContext.OpenElement("MyElement"); theContext.InsertContent("A dummy content"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL( std::string("A dummy content"), mTargetStream.str()); } void testCloseElement_whenHasChildren() { XmlWriteContext theContext(mTargetStream); theContext.OpenElement("MyElement"); theContext.OpenElement("Child"); theContext.InsertContent("A dummy content"); theContext.CloseElement("Child"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL( std::string("A dummy content"), mTargetStream.str()); } void testCloseElement_whenHasSiblings() { XmlWriteContext theContext(mTargetStream); theContext.OpenElement("MyElement"); theContext.OpenElement("Child1"); theContext.CloseElement("Child1"); theContext.OpenElement("Child2"); theContext.InsertContent("A dummy content"); theContext.CloseElement("Child2"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL( std::string("A dummy content"), mTargetStream.str()); } void testInsertAttribute_whenOutsideTheTagFails() { XmlWriteContext theContext(mTargetStream); try { theContext.InsertAttribute("anAttribute","value"); CPPUNIT_FAIL("The assertion should have failed"); } catch (CLAM::ErrAssertionFailed & err) { CPPUNIT_ASSERT_EQUAL(std::string("Appending attribute outside a tag"), std::string(err.what())); } } void testInsertAttribute_whenEmpty() { XmlWriteContext theContext(mTargetStream); theContext.OpenElement("MyElement"); theContext.InsertAttribute("anAttribute","value"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL( std::string(""), mTargetStream.str()); } void testInsertAttribute_whenFull() { XmlWriteContext theContext(mTargetStream); theContext.OpenElement("MyElement"); theContext.InsertAttribute("anAttribute","value"); theContext.OpenElement("Child"); theContext.InsertContent("A dummy content"); theContext.CloseElement("Child"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL( std::string("A dummy content"), mTargetStream.str()); } void testCurrentLevel_whenConstructed() { XmlWriteContext theContext(mTargetStream); CPPUNIT_ASSERT_EQUAL(0u, theContext.CurrentLevel()); } void testCurrentLevel_whenContentAdded() { XmlWriteContext theContext(mTargetStream); theContext.InsertContent("A dummy content"); CPPUNIT_ASSERT_EQUAL(0u, theContext.CurrentLevel()); } void testCurrentLevel_whenElementOpened() { XmlWriteContext theContext(mTargetStream); theContext.OpenElement("MyElement"); CPPUNIT_ASSERT_EQUAL(1u, theContext.CurrentLevel()); } void testCurrentLevel_whenTwoElementsOpened() { XmlWriteContext theContext(mTargetStream); theContext.OpenElement("MyElement"); theContext.OpenElement("OtherElement"); CPPUNIT_ASSERT_EQUAL(2u, theContext.CurrentLevel()); } void testCurrentLevel_whenOneElementClosed() { XmlWriteContext theContext(mTargetStream); theContext.OpenElement("MyElement"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL(0u, theContext.CurrentLevel()); } void testCurrentLevel_whenTwoElementClosed() { XmlWriteContext theContext(mTargetStream); theContext.OpenElement("MyElement"); theContext.OpenElement("OtherElement"); theContext.CloseElement("OtherElement"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL(0u, theContext.CurrentLevel()); } void testCurrentLevel_whenFirstOfTwoElementClosed() { XmlWriteContext theContext(mTargetStream); theContext.OpenElement("MyElement"); theContext.OpenElement("OtherElement"); theContext.CloseElement("OtherElement"); CPPUNIT_ASSERT_EQUAL(1u, theContext.CurrentLevel()); } void testIndentation_whenSingleContent() { XmlWriteContext theContext(mTargetStream); theContext.UseIndentation(true); theContext.InsertContent("A dummy content"); CPPUNIT_ASSERT_EQUAL(std::string( "A dummy content" ), mTargetStream.str()); } void testIndentation_whenSingleElement() { XmlWriteContext theContext(mTargetStream); theContext.UseIndentation(true); theContext.OpenElement("MyElement"); CPPUNIT_ASSERT_EQUAL(std::string( "\n" "" ), mTargetStream.str()); } void testIndentation_whenNested() { XmlWriteContext theContext(mTargetStream); theContext.UseIndentation(true); theContext.OpenElement("MyElement"); theContext.OpenElement("OtherElement"); theContext.CloseElement("OtherElement"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL(std::string( "\n" "\t\n" "" ), mTargetStream.str()); } void testIndentation_whenNestedSiblings() { XmlWriteContext theContext(mTargetStream); theContext.UseIndentation(true); theContext.OpenElement("MyElement"); theContext.OpenElement("OtherElement"); theContext.CloseElement("OtherElement"); theContext.OpenElement("TheElement"); theContext.CloseElement("TheElement"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL(std::string( "\n" "\t\n" "\t\n" "" ), mTargetStream.str()); } void testIndentation_whenNestedSingleContent() { XmlWriteContext theContext(mTargetStream); theContext.UseIndentation(true); theContext.OpenElement("MyElement"); theContext.InsertContent("A dummy content"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL(std::string( "A dummy content" ), mTargetStream.str()); } void testIndentation_whenNestedPreContent() { XmlWriteContext theContext(mTargetStream); theContext.UseIndentation(true); theContext.OpenElement("MyElement"); theContext.InsertContent("A dummy content"); theContext.OpenElement("OtherElement"); theContext.CloseElement("OtherElement"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL(std::string( "A dummy content\n" "\t\n" "" ), mTargetStream.str()); } void testIndentation_whenNestedPostContent() { XmlWriteContext theContext(mTargetStream); theContext.UseIndentation(true); theContext.OpenElement("MyElement"); theContext.OpenElement("OtherElement"); theContext.CloseElement("OtherElement"); theContext.InsertContent("A dummy content"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL(std::string( "\n" "\t\n" "\tA dummy content\n" "" ), mTargetStream.str()); } void testIndentation_whenNestedNested() { XmlWriteContext theContext(mTargetStream); theContext.UseIndentation(true); theContext.OpenElement("MyElement"); theContext.OpenElement("OtherElement"); theContext.OpenElement("TheElement"); theContext.InsertContent("A dummy content"); theContext.CloseElement("TheElement"); theContext.CloseElement("OtherElement"); theContext.CloseElement("MyElement"); CPPUNIT_ASSERT_EQUAL(std::string( "\n" "\t\n" "\t\tA dummy content\n" "\t\n" "" ), mTargetStream.str()); } }; } // namespace Test } // namespace Cuidado clam-1.4.0/test/UnitTests/XmlTests/LibXmlDomReadingContextTest.cxx0000644000000000000000000004752211160511615023713 0ustar rootroot#ifdef USE_XMLPP #include #include "cppUnitHelper.hxx" #include "XMLStorage.hxx" // CLAM #include "XmlMockUpObjects.hxx" // CLAM #include "Component.hxx" // CLAM #include #include "LibXmlDomReadingContext.hxx" // CLAM #include "LibXmlDomWriter.hxx" // CLAM #include "LibXmlDomReader.hxx" // CLAM /* TOTEST: - A comment doesn't break content - Any non-comment node does break content - Spaces at the begining of content are eaten - Attributes support */ namespace CLAM { namespace Test { class LibXmlDomReadingContextTest; CPPUNIT_TEST_SUITE_REGISTRATION( LibXmlDomReadingContextTest ); class LibXmlDomReadingContextTest : public CppUnit::TestCase { CPPUNIT_TEST_SUITE( LibXmlDomReadingContextTest ); CPPUNIT_TEST(testFetchContent_withASingleWordContent); CPPUNIT_TEST(testFetchContent_withTwoJointContents); CPPUNIT_TEST(testFetchContent_withTwoContentsSeparatedByElement); CPPUNIT_TEST(testFetchContent_withTwoContentsSeparatedByComment); CPPUNIT_TEST(testFetchContent_withNoNode); CPPUNIT_TEST(testFetchContent_withElementFirst); CPPUNIT_TEST(testContentLeft_withNoNode_returnsFalse); CPPUNIT_TEST(testContentLeft_withNonSpaceReturnsTrue); CPPUNIT_TEST(testContentLeft_withStartingSpacesAndNonSpace_chopsAndReturnsTrue); CPPUNIT_TEST(testContentLeft_withOnlySpaces_chopsAndReturnsFalse); CPPUNIT_TEST(testFindElement_withThatElementFirst); CPPUNIT_TEST(testFindElement_withWrongNameFails); CPPUNIT_TEST(testFindElement_withCommentBefore); CPPUNIT_TEST(testFindElement_withNoElement); CPPUNIT_TEST(testFindElement_withTextFirst); CPPUNIT_TEST(testFindElement_withReadedTextFirst); CPPUNIT_TEST(testFindElement_withHalfReadedTextFirst); CPPUNIT_TEST(testFindElement_withSpacesToReadFirst); // CPPUNIT_TEST(testFindElement_withStillNonElement_asserts); CPPUNIT_TEST(testFetchElement_withThatElementFirst); CPPUNIT_TEST(testFetchElement_withSecondElementFirst); CPPUNIT_TEST(testFetchElement_withTextFirst); CPPUNIT_TEST(testFetchElement_withNoElement); CPPUNIT_TEST(testFetchElement_withADifferentName); // CPPUNIT_TEST(testFetchElement_withANonElementNode); CPPUNIT_TEST(testFetchContent_afterElement); CPPUNIT_TEST(testFetchContent_whenSecondElement); CPPUNIT_TEST(testFetchContent_afterElementWithSpaces); CPPUNIT_TEST(testReleaseContext_atRootReturnsNull); CPPUNIT_TEST(testReleaseContext_whenIsChildContext); CPPUNIT_TEST(testRecursiveConstructor_initializesTheContext); CPPUNIT_TEST(testReleaseContext_whenContentLeft); CPPUNIT_TEST(testReleaseContext_whenElementLeft); CPPUNIT_TEST(testExtractAttribute_whenNone); CPPUNIT_TEST(testExtractAttribute_whenPresent); CPPUNIT_TEST(testExtractAttribute_withDifferentAttributeName); CPPUNIT_TEST(testGetPath); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { mTargetStream.str(""); mDocument = new xmlpp::Document; mRoot = mDocument->create_root_node( "TestDoc" // root element name // ,"http://iua.upf.es/mtg/clam/0.8.0/2005-06" // root element namespace URI. // ,"clam" // namespace prefix ); } /// Common clean up, executed after each test method void tearDown() { delete mDocument; } private: std::stringstream mTargetStream; xmlpp::Document * mDocument; xmlpp::Element * mRoot; void testFetchContent_withASingleWordContent() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_text("Content"); LibXmlDomReadingContext context(contextElement); std::string content; std::getline(context.reachableContent(), content); CPPUNIT_ASSERT_EQUAL(std::string("Content"),content); } void testFetchContent_withTwoJointContents() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_text("Content1"); contextElement->add_child_text("Content2"); LibXmlDomReadingContext context(contextElement); std::string content; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(std::string("Content1Content2"),content); } void testFetchContent_withTwoContentsSeparatedByElement() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_text("Content1"); contextElement->add_child("Separator"); contextElement->add_child_text("Content2"); LibXmlDomReadingContext context(contextElement); std::string content; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(std::string("Content1"),content); } void testFetchContent_withTwoContentsSeparatedByComment() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_text("Content1"); contextElement->add_child_comment("Separator"); contextElement->add_child_text("Content2"); LibXmlDomReadingContext context(contextElement); std::string content; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(std::string("Content1Content2"),content); } void testFetchContent_withNoNode() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); LibXmlDomReadingContext context(contextElement); std::string content="rubbish"; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(true,stream.fail()); CPPUNIT_ASSERT_EQUAL(std::string(""),content); } void testFetchContent_withElementFirst() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child("UnexpectedElement"); contextElement->add_child_text("Content"); LibXmlDomReadingContext context(contextElement); std::string content="rubbish"; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT(stream.fail()); CPPUNIT_ASSERT_EQUAL(std::string(""),content); } void testContentLeft_withNoNode_returnsFalse() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); LibXmlDomReadingContext context(contextElement); std::string content="rubbish"; bool charactersLeft = context.contentLeft(); CPPUNIT_ASSERT(!charactersLeft); } void testContentLeft_withNonSpaceReturnsTrue() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_text("Content"); LibXmlDomReadingContext context(contextElement); bool charactersLeft = context.contentLeft(); CPPUNIT_ASSERT(charactersLeft); std::string content="rubbish"; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(std::string("Content"),content); } void testContentLeft_withStartingSpacesAndNonSpace_chopsAndReturnsTrue() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_text(" \t \n Content"); LibXmlDomReadingContext context(contextElement); bool charactersLeft = context.contentLeft(); CPPUNIT_ASSERT(charactersLeft); std::string content="rubbish"; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(std::string("Content"),content); } void testContentLeft_withOnlySpaces_chopsAndReturnsFalse() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_text(" \t \n "); LibXmlDomReadingContext context(contextElement); bool charactersLeft = context.contentLeft(); CPPUNIT_ASSERT(!charactersLeft); std::string content="rubbish"; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(std::string(""),content); } void testFindElement_withThatElementFirst() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child("Element"); LibXmlDomReadingContext context(contextElement); bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(foundElement); } void testFindElement_withWrongNameFails() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child("Wrong"); contextElement->add_child("Element"); LibXmlDomReadingContext context(contextElement); bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(!foundElement); } void testFindElement_withCommentBefore() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_comment("Separator"); contextElement->add_child("Element"); LibXmlDomReadingContext context(contextElement); bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(foundElement); } void testFindElement_withNoElement() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); LibXmlDomReadingContext context(contextElement); bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(!foundElement); } void testFindElement_withTextFirst() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_text("ContentLeft"); contextElement->add_child("Element"); LibXmlDomReadingContext context(contextElement); bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(!foundElement); } void testFindElement_withReadedTextFirst() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_text("ReadingContent"); contextElement->add_child("Element"); LibXmlDomReadingContext context(contextElement); std::string content; context.reachableContent() >> content; bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(foundElement); CPPUNIT_ASSERT_EQUAL(std::string("ReadingContent"), content); } void testFindElement_withHalfReadedTextFirst() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_text("Reading Content"); contextElement->add_child("Element"); LibXmlDomReadingContext context(contextElement); std::string content; context.reachableContent() >> content; bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(!foundElement); CPPUNIT_ASSERT_EQUAL(std::string("Reading"), content); } void testFindElement_withSpacesToReadFirst() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_text(" \n \t \t \r "); contextElement->add_child("Element"); LibXmlDomReadingContext context(contextElement); bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(foundElement); } // TODO: This test can not be implemented because you cannot add PI's with libxml /* void testFindElement_withStillNonElement_asserts() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_processing_instruction("ProcessingInstruction","Content"); LibXmlDomReadingContext context(contextElement); try { context.findElement("Element"); CPPUNIT_FAIL("Should have failed an assertion"); } catch (ErrAssertionFailed & e) { CPPUNIT_ASSERT_EQUAL( std::string("Can't change the context to a non element node"), std::string(e.what())); } } */ void testFetchElement_withThatElementFirst() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); xmlpp::Element * domElement = contextElement->add_child("Element"); LibXmlDomReadingContext context(contextElement); xmlpp::Element * foundElement = context.fetchElement("Element"); CPPUNIT_ASSERT_EQUAL(domElement, foundElement); } void testFetchElement_withSecondElementFirst() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); xmlpp::Element * domElement1 = contextElement->add_child("Element1"); xmlpp::Element * domElement2 = contextElement->add_child("Element2"); LibXmlDomReadingContext context(contextElement); xmlpp::Element * foundElement1 = context.fetchElement("Element1"); xmlpp::Element * foundElement2 = context.fetchElement("Element2"); CPPUNIT_ASSERT_EQUAL(domElement2, foundElement2); CPPUNIT_ASSERT_EQUAL(domElement1, foundElement1); } void testFetchElement_withTextFirst() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_text("ContentLeft"); contextElement->add_child("Element"); LibXmlDomReadingContext context(contextElement); try { xmlpp::Element * foundElement = context.fetchElement("Element"); CPPUNIT_FAIL("Should have failed an assertion"); foundElement = 0; // To stop warnings } catch (ErrAssertionFailed & e) { CPPUNIT_ASSERT_EQUAL( std::string("Fetching element with content left"), std::string(e.what())); } } void testFetchElement_withNoElement() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child("Element"); LibXmlDomReadingContext context(contextElement); context.fetchElement("Element"); try { context.fetchElement("Element"); CPPUNIT_FAIL("Should have failed an assertion"); } catch (ErrAssertionFailed & e) { CPPUNIT_ASSERT_EQUAL( std::string("Accessing beyond DOM nodes"), std::string(e.what())); } } void testFetchElement_withADifferentName() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child("Element"); LibXmlDomReadingContext context(contextElement); try { context.fetchElement("WrongElement"); CPPUNIT_FAIL("Should have failed an assertion"); } catch (ErrAssertionFailed & e) { CPPUNIT_ASSERT_EQUAL( std::string("XML element name should be the one expected"), std::string(e.what())); } } // TODO: This test can not be implemented because you cannot add PI's with libxml /* void testFetchElement_withANonElementNode() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_processing_instruction("ProcessingInstruction","Content"); LibXmlDomReadingContext context(contextElement); try { context.fetchElement("Element"); CPPUNIT_FAIL("Should have failed an assertion"); } catch (ErrAssertionFailed & e) { CPPUNIT_ASSERT_EQUAL( std::string("Can't change the context to a non element node"), std::string(e.what())); } } */ void testFetchContent_afterElement() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_text("Content1"); contextElement->add_child("Element"); contextElement->add_child_text("Content2"); LibXmlDomReadingContext context(contextElement); std::string content1="rubbish"; std::getline(context.reachableContent(), content1); context.fetchElement("Element"); std::string content2="rubbish"; std::getline(context.reachableContent(), content2); CPPUNIT_ASSERT_EQUAL(std::string("Content2"),content2); } void testFetchContent_whenSecondElement() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child("Element1"); contextElement->add_child("Element2"); LibXmlDomReadingContext context(contextElement); context.fetchElement("Element1"); std::istream & stream = context.reachableContent(); std::string content="rubbish"; std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(true,stream.fail()); CPPUNIT_ASSERT_EQUAL(std::string(""),content); } void testFetchContent_afterElementWithSpaces() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child("Element"); contextElement->add_child_text(" Content"); LibXmlDomReadingContext context(contextElement); context.fetchElement("Element"); std::string content2="rubbish"; std::getline(context.reachableContent(), content2); CPPUNIT_ASSERT_EQUAL(std::string("Content"),content2); } void testReleaseContext_atRootReturnsNull() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); LibXmlDomReadingContext context(contextElement); LibXmlDomReadingContext * previous = context.release(); CPPUNIT_ASSERT_EQUAL((LibXmlDomReadingContext*)0, previous); } void testReleaseContext_whenIsChildContext() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child("Element"); LibXmlDomReadingContext context1(contextElement); LibXmlDomReadingContext context2(&context1,"Element"); LibXmlDomReadingContext * previous = context2.release(); CPPUNIT_ASSERT_EQUAL(&context1, previous); } void testRecursiveConstructor_initializesTheContext() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); xmlpp::Element * outerElement = contextElement->add_child("Element"); xmlpp::Element * innerElement = outerElement->add_child("InnerElement"); LibXmlDomReadingContext contextRoot(contextElement); LibXmlDomReadingContext contextInner(&contextRoot,"Element"); xmlpp::Element * foundElement = contextInner.fetchElement("InnerElement"); CPPUNIT_ASSERT_EQUAL(innerElement, foundElement); } void testReleaseContext_whenContentLeft() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child_text("Offending input\none line more"); LibXmlDomReadingContext context(contextElement); context.release(); std::list errors = context.errors(); std::string result; for (std::list::iterator it=errors.begin(); it!=errors.end(); it++) result+= *it + '\n'; CPPUNIT_ASSERT_EQUAL(std::string( "Unexpected content: 'Offending input\none line more' at position /TestDoc/ContextElement\n"), result ); } void testReleaseContext_whenElementLeft() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->add_child("Element"); contextElement->add_child("Offender"); LibXmlDomReadingContext context(contextElement); context.fetchElement("Element"); context.release(); std::list errors = context.errors(); std::string result; for (std::list::iterator it=errors.begin(); it!=errors.end(); it++) result+= *it + '\n'; CPPUNIT_ASSERT_EQUAL(std::string( "Unexpected Element: 'Offender' at position /TestDoc/ContextElement\n"), result ); } void testRelease_whenANonElementAndNonContentNodeLeft() { // TODO } void testExtractAttribute_whenNone() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); LibXmlDomReadingContext context(contextElement); std::stringstream stream; bool result = context.extractAttribute("Unexistent", stream); CPPUNIT_ASSERT_MESSAGE("Should have been false",!result); } void testExtractAttribute_whenPresent() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->set_attribute("Attribute","AttributeValue"); LibXmlDomReadingContext context(contextElement); std::stringstream stream; bool result = context.extractAttribute("Attribute", stream); CPPUNIT_ASSERT_MESSAGE("Should have been true",result); std::string extractedValue; stream >> extractedValue; CPPUNIT_ASSERT_EQUAL(std::string("AttributeValue"),extractedValue); } void testExtractAttribute_withDifferentAttributeName() { xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement->set_attribute("Attribute","AttributeValue"); LibXmlDomReadingContext context(contextElement); std::stringstream stream; bool result = context.extractAttribute("WrongAttribute", stream); CPPUNIT_ASSERT_MESSAGE("Should have been false",!result); } void testGetPath() { LibXmlDomReader reader; xmlpp::Element * contextElement = mRoot->add_child("ContextElement"); contextElement ->add_child("Element1") ->add_child("Element2") ->add_child("Element3"); LibXmlDomReadingContext context0(contextElement); LibXmlDomReadingContext context1(&context0,"Element1"); LibXmlDomReadingContext context2(&context1,"Element2"); LibXmlDomReadingContext context3(&context2,"Element3"); std::string path = context3.getPath(); CPPUNIT_ASSERT_EQUAL(std::string("/TestDoc/ContextElement/Element1/Element2/Element3"),path); } }; } // namespace Test } // namespace Cuidado #endif//USE_XMLPP clam-1.4.0/test/UnitTests/XmlTests/XmlScopedTest.cxx0000644000000000000000000000661610442000724021116 0ustar rootroot#include #include "cppUnitHelper.hxx" #include #include "XmlScoped.hxx" // CLAM namespace CLAM { namespace Test { class XmlScopedTest; CPPUNIT_TEST_SUITE_REGISTRATION( XmlScopedTest ); class XmlScopedTest : public CppUnit::TestCase { CPPUNIT_TEST_SUITE( XmlScopedTest ); CPPUNIT_TEST( testInsertInteger ); CPPUNIT_TEST( testInsertString ); CPPUNIT_TEST( testEmptyElement ); CPPUNIT_TEST( testElementWithContent ); CPPUNIT_TEST( testEmptyElementWithAttribute ); CPPUNIT_TEST( testEmptyElementWithFloatAttribute ); CPPUNIT_TEST( testElementWithAttributeAndContent ); CPPUNIT_TEST( testElementWithAttributes ); CPPUNIT_TEST( testElementWithChildren ); // CPPUNIT_TEST( test ); // CPPUNIT_TEST( test ); // CPPUNIT_TEST( test ); // CPPUNIT_TEST( test ); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { mTargetStream.str(""); } /// Common clean up, executed after each test method void tearDown() { } private: std::stringstream mTargetStream; void testInsertInteger() { XmlFragment theContext(mTargetStream); XmlContent content(3); CPPUNIT_ASSERT_EQUAL(std::string("3"), mTargetStream.str()); } void testInsertString() { XmlFragment theContext(mTargetStream); XmlContent content("A dummy text"); CPPUNIT_ASSERT_EQUAL(std::string("A dummy text"), mTargetStream.str()); } void testEmptyElement() { XmlFragment theContext(mTargetStream); { XmlElement tag1("Tag1"); } CPPUNIT_ASSERT_EQUAL(std::string(""), mTargetStream.str()); } void testElementWithContent() { XmlFragment theContext(mTargetStream); { XmlElement tag1("Tag1"); XmlContent content("A dummy text"); } CPPUNIT_ASSERT_EQUAL( std::string("A dummy text"), mTargetStream.str()); } void testEmptyElementWithAttribute() { XmlFragment theContext(mTargetStream); { XmlElement tag1("Tag1"); XmlAttribute a("attrib11","value11"); } CPPUNIT_ASSERT_EQUAL( std::string(""), mTargetStream.str()); } void testEmptyElementWithFloatAttribute() { XmlFragment theContext(mTargetStream); { XmlElement tag1("Tag1"); XmlAttribute a("attrib11",2.34343); } CPPUNIT_ASSERT_EQUAL( std::string(""), mTargetStream.str()); } void testElementWithAttributeAndContent() { XmlFragment theContext(mTargetStream); { XmlElement tag1("Tag1"); XmlAttribute a("attrib11","value11"); XmlContent content("A dummy text"); } CPPUNIT_ASSERT_EQUAL( std::string("A dummy text"), mTargetStream.str()); } void testElementWithAttributes() { XmlFragment theContext(mTargetStream); { XmlElement tag1("Tag1"); XmlAttribute a1("attrib11","value11"); XmlAttribute a2("attrib12","value12"); XmlContent content("A dummy text"); } CPPUNIT_ASSERT_EQUAL( std::string("" "A dummy text"), mTargetStream.str()); } void testElementWithChildren() { XmlFragment theContext(mTargetStream); { XmlElement tag1("Tag1"); { XmlElement tag11("Tag11"); XmlContent content("A dummy text"); } { XmlElement tag12("Tag12"); } } CPPUNIT_ASSERT_EQUAL( std::string("A dummy text"), mTargetStream.str()); } }; } // namespace Test } // namespace CLAM clam-1.4.0/test/UnitTests/XmlTests/ClamObjects2XercesDomTest.cxx0000644000000000000000000002446410630505361023311 0ustar rootroot#ifdef USE_XERCES #include #include "cppUnitHelper.hxx" #include "XMLStorage.hxx" // CLAM #include "XmlMockUpObjects.hxx" namespace CLAM { namespace Test { class ClamObjectsToXercesDomTest; CPPUNIT_TEST_SUITE_REGISTRATION( ClamObjectsToXercesDomTest ); class ClamObjectsToXercesDomTest : public CppUnit::TestCase { CPPUNIT_TEST_SUITE( ClamObjectsToXercesDomTest ); CPPUNIT_TEST(testEmptyDocument); CPPUNIT_TEST(testBasicAsPlainContent); CPPUNIT_TEST(testBasicAsElement_withoutContent); CPPUNIT_TEST(testBasicAsElement_withContent); CPPUNIT_TEST(testBasicAsPlainContent_withoutContent); CPPUNIT_TEST(testBasicAsAttribute); CPPUNIT_TEST(testComponentAsPlainContent); CPPUNIT_TEST(testComponentAsElement_withoutContent); CPPUNIT_TEST(testComponentAsElement_withContent); CPPUNIT_TEST(testComponentAsPlainContent_withoutContent); CPPUNIT_TEST(testComponentAsAttribute); CPPUNIT_TEST(testSibblingsContentsAndAttributes_getOrderedAsInserted); CPPUNIT_TEST(testConsecutiveContents_getSpaceSeparation); CPPUNIT_TEST(testNonConsecutiveContents_dontGetSpaceSeparation); CPPUNIT_TEST(testSibblingsAttributes_getReordered); CPPUNIT_TEST(testComponentAsElement_containingBasicAsPlainContent); CPPUNIT_TEST(testElementContents_getPrintedBeforeSiblingContent); CPPUNIT_TEST(testNodesInsertionAfterComponentElement); CPPUNIT_TEST(testComponentAsElement_containingBasicAsAttribute); CPPUNIT_TEST(testComponentAsElement_containingBasicAsElement); CPPUNIT_TEST(testComponentAsElement_containingComponentAsElement); CPPUNIT_TEST(testComponentAsContent_containingBasicAsPlainContent); CPPUNIT_TEST(testComponentAsContent_containingBasicAsAttribute); CPPUNIT_TEST(testComponentAsContent_containingBasicAsElement); CPPUNIT_TEST(testComponentAsAttribute_containingAnything_childrenHaveNoEffect); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: std::stringstream mTargetStream; void assertDumpAs(const Component & toStore, const std::string & expected) { XMLStorage dumper; dumper.Create("Doc"); dumper.DumpObject(toStore); dumper.WriteSelection(mTargetStream); CPPUNIT_ASSERT_EQUAL(expected, mTargetStream.str()); } void testEmptyDocument() { CompositeOfXmlables toStore; assertDumpAs(toStore,""); } void testBasicAsPlainContent() { CompositeOfXmlables toStore; XmlMockUpBasic basic; basic.setContent("Content"); toStore.add(basic); assertDumpAs(toStore,"Content"); } void testBasicAsPlainContent_withoutContent() { CompositeOfXmlables toStore; XmlMockUpBasic basic; toStore.add(basic); assertDumpAs(toStore,""); } void testBasicAsElement_withoutContent() { CompositeOfXmlables toStore; XmlMockUpBasic basic("Element",true); toStore.add(basic); assertDumpAs(toStore,""); } void testBasicAsElement_withContent() { CompositeOfXmlables toStore; XmlMockUpBasic basic("Element",true); basic.setContent("Content"); toStore.add(basic); assertDumpAs(toStore,"Content"); } void testBasicAsAttribute() { CompositeOfXmlables toStore; XmlMockUpBasic basic("at",false); basic.setContent("Content"); toStore.add(basic); assertDumpAs(toStore,""); } void testComponentAsPlainContent() { CompositeOfXmlables toStore; XmlMockUpComponent component; component.setContent("Content"); toStore.add(component); assertDumpAs(toStore,"Content"); } void testComponentAsPlainContent_withoutContent() { CompositeOfXmlables toStore; XmlMockUpComponent component; toStore.add(component); assertDumpAs(toStore,""); } void testComponentAsElement_withoutContent() { CompositeOfXmlables toStore; XmlMockUpComponent component("Element",true); toStore.add(component); assertDumpAs(toStore,""); } void testComponentAsElement_withContent() { CompositeOfXmlables toStore; XmlMockUpComponent component("Element",true); component.setContent("Content"); toStore.add(component); assertDumpAs(toStore,"Content"); } void testComponentAsAttribute() { CompositeOfXmlables toStore; XmlMockUpComponent component("at",false); component.setContent("Content"); toStore.add(component); assertDumpAs(toStore,""); } void testSibblingsContentsAndAttributes_getOrderedAsInserted() { CompositeOfXmlables toStore; XmlMockUpBasic oneElement("OneElement",true); XmlMockUpBasic otherElement("OtherElement",true); XmlMockUpBasic content; content.setContent("Content"); toStore.add(oneElement); toStore.add(content); toStore.add(otherElement); assertDumpAs(toStore,"Content"); } void testConsecutiveContents_getSpaceSeparation() { CompositeOfXmlables toStore; XmlMockUpBasic content1; content1.setContent("Content1"); XmlMockUpBasic content2; content2.setContent("Content2"); toStore.add(content1); toStore.add(content2); assertDumpAs(toStore,"Content1 Content2"); } void testNonConsecutiveContents_dontGetSpaceSeparation() { CompositeOfXmlables toStore; XmlMockUpBasic content1; content1.setContent("Content1"); XmlMockUpBasic content2; XmlMockUpBasic element("Element",true); content2.setContent("Content2"); toStore.add(content1); toStore.add(element); toStore.add(content2); assertDumpAs(toStore,"Content1Content2"); } void testSibblingsAttributes_getReordered() { CompositeOfXmlables toStore; // Not a requirement, just to check the behabiour XmlMockUpBasic attribute1("zFirst"); attribute1.setContent("Content1"); XmlMockUpBasic attribute2("aSecond"); attribute2.setContent("Content2"); toStore.add(attribute1); toStore.add(attribute2); assertDumpAs(toStore,""); } void testComponentAsElement_containingBasicAsPlainContent() { CompositeOfXmlables toStore; XmlMockUpBasic content; content.setContent("Content"); XmlMockUpComponent element("Element",true); element.add(content); toStore.add(element); assertDumpAs(toStore,"Content"); } void testElementContents_getPrintedBeforeSiblingContent() { CompositeOfXmlables toStore; XmlMockUpBasic content; content.setContent("Content"); XmlMockUpComponent element("Element",true); element.setContent("ElementContent"); element.add(content); toStore.add(element); assertDumpAs(toStore,"ElementContent Content"); } void testNodesInsertionAfterComponentElement() { CompositeOfXmlables toStore; XmlMockUpBasic content; content.setContent("Content"); XmlMockUpComponent element("Element",true); XmlMockUpBasic afterContent; afterContent.setContent("AfterContent"); element.add(content); toStore.add(element); toStore.add(afterContent); assertDumpAs(toStore,"ContentAfterContent"); } void testComponentAsElement_containingBasicAsAttribute() { CompositeOfXmlables toStore; XmlMockUpComponent element("Element",true); XmlMockUpBasic attribute("at"); attribute.setContent("atContent"); element.add(attribute); toStore.add(element); assertDumpAs(toStore,""); } void testComponentAsElement_containingBasicAsElement() { CompositeOfXmlables toStore; XmlMockUpComponent componentElement("Component",true); componentElement.setContent("ComponentContent"); XmlMockUpBasic basicElement("Basic",true); basicElement.setContent("BasicContent"); componentElement.add(basicElement); toStore.add(componentElement); assertDumpAs(toStore, "ComponentContent" "BasicContent"""); } void testComponentAsElement_containingComponentAsElement() { CompositeOfXmlables toStore; XmlMockUpComponent outsideElement("Outside",true); outsideElement.setContent("ComponentContent"); XmlMockUpComponent insideElement("Inside",true); insideElement.setContent("InsideContent"); outsideElement.add(insideElement); toStore.add(outsideElement); assertDumpAs(toStore, "ComponentContent" "InsideContent"); } void testComponentAsContent_containingBasicAsPlainContent() { CompositeOfXmlables toStore; XmlMockUpComponent componentContent; componentContent.setContent("ComponentContent"); XmlMockUpBasic basicContent; basicContent.setContent("BasicContent"); componentContent.add(basicContent); toStore.add(componentContent); assertDumpAs(toStore,"ComponentContent BasicContent"); } void testComponentAsContent_containingBasicAsAttribute() { CompositeOfXmlables toStore; XmlMockUpComponent componentContent; componentContent.setContent("ComponentContent"); XmlMockUpBasic basicAttribute("at"); basicAttribute.setContent("BasicContent"); componentContent.add(basicAttribute); toStore.add(componentContent); assertDumpAs(toStore,"ComponentContent"); } void testComponentAsContent_containingBasicAsElement() { CompositeOfXmlables toStore; XmlMockUpComponent componentContent; componentContent.setContent("ComponentContent"); XmlMockUpBasic basicElement("Basic",true); basicElement.setContent("BasicContent"); componentContent.add(basicElement); toStore.add(componentContent); assertDumpAs(toStore,"ComponentContentBasicContent"); } void testComponentAsAttribute_containingAnything_childrenHaveNoEffect() { CompositeOfXmlables toStore; XmlMockUpComponent componentAttribute("componentAttribute"); componentAttribute.setContent("ComponentContent"); XmlMockUpBasic basicElement("BasicElement",true); basicElement.setContent("BasicElementContent"); XmlMockUpBasic basicAttribute("BasicAttribute",true); basicElement.setContent("BasicAttributeContent"); XmlMockUpBasic basicContent; basicContent.setContent("BasicContentContent"); componentAttribute.add(basicElement); componentAttribute.add(basicAttribute); componentAttribute.add(basicContent); toStore.add(componentAttribute); assertDumpAs(toStore,""); } }; } // namespace Test } // namespace Cuidado #endif //USE_XERCES clam-1.4.0/test/UnitTests/XmlTests/AdaptersTest.cxx0000644000000000000000000004664111122320455020767 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /** * @file * This file contains tests that checks that the XMLAdapters do their work, * that is to adapt objects to something a XMLStorage can manage for Loading * and Storing. * @todo Refactor code duplication * @todo Array of basic objects XML test * @todo List of basic objects XML test */ #include "XMLAdapter.hxx" // CLAM #include "XMLArrayAdapter.hxx" // CLAM #include "XMLComponentAdapter.hxx" // CLAM #include "XMLIterableAdapter.hxx" // CLAM #include "XMLStorage.hxx" // CLAM #include "Array.hxx" // CLAM #include "List.hxx" // CLAM #include "XMLTestHelper.hxx" #include #include #include //#include #include using namespace CLAM; namespace CLAMTest { class XmlAdaptersTest; CPPUNIT_TEST_SUITE_REGISTRATION( XmlAdaptersTest ); /** * This a component which simulates containing some XML adapters TestCases. * It check the effectiveness of the Store/Load pair for the XML adapter. * It will store default constructed TestCases, and then will load * over a non-default constructed TestCases that can be compared * to the default one. */ template class GenericAdaptersTester : public Component { std::string mId; public: GenericAdaptersTester() { mId=TestCase::kind(); } void StoreOn(Storage & storer) const { TestCase a(true), b(true), c(true); a.AdaptToStore(storer,true,false); // Content b.AdaptToStore(storer,false,false); // Attribute c.AdaptToStore(storer,false,true); // Element } void LoadFrom(Storage & storer) { // For each insertion mode (attribute-element-content) { TestCase a, b(true); a.AdaptToLoad(storer,true,false); // Content std::string context("Loading Content "+mId); bool failed = a.DiferenceCause(b,context); CLAM_ASSERT(!failed, context.c_str()); } { TestCase a, b(true); a.AdaptToLoad(storer,false,false); // Attribute std::string context("Loading Attribute "+mId); bool failed = a.DiferenceCause(b,context); CLAM_ASSERT(!failed, context.c_str()); } { TestCase a, b(true); a.AdaptToLoad(storer,false,true); // Element std::string context("Loading Element "+mId); bool failed = a.DiferenceCause(b,context); CLAM_ASSERT(!failed, context.c_str()); } } const char * GetClassName() const { return "GenericAdaptersTester"; } }; class SimpleAdapterTestCase { public: int i; double d; char c; std::string s; static const char * kind() {return "Simple Adapter";} SimpleAdapterTestCase(bool b) { i = 3; d = 3.5; c = 'a'; s = "Hola"; } SimpleAdapterTestCase() { i = 6; d = 6.5; c = 'b'; s = "Adios"; } bool DiferenceCause(const SimpleAdapterTestCase & other, std::string &context) const { bool areDifferent = false; std::stringstream out; if (i!=other.i) { out << "Int value mismatch:" << " Found " << i << " Expected " << other.i << std::endl; areDifferent = true; } if (d!=other.d) { out << "Double value mismatch:" << " Found " << d << " Expected " << other.d << std::endl; areDifferent = true; } if (c!=other.c) { out << "Char value mismatch:" << " Found " << c << " Expected " << other.c << std::endl; areDifferent = true; } if (std::string(s)!=std::string(other.s)) { out << "String value mismatch:" << " Found " << s << " Expected " << other.s << std::endl; areDifferent = true; } context += out.str(); return areDifferent; } void AdaptToStore(Storage & storer, bool asContent, bool asElement) { CLAM_ASSERT(!(asContent && asElement), "Testing logic calling in AdaptToStore"); XMLAdapter intAdapter(i, asContent?0:"myInt", asElement); storer.Store(intAdapter); XMLAdapter doubleAdapter(d, asContent?0:"myDouble", asElement); storer.Store(doubleAdapter); XMLAdapter charAdapter(c, asContent?0:"myChar", asElement); storer.Store(charAdapter); XMLAdapter strAdapter(s, asContent?0:"myString", asElement); storer.Store(strAdapter); } void AdaptToLoad(Storage & storer, bool asContent, bool asElement) { CLAM_ASSERT(!(asContent && asElement), "Testing logic calling in AdaptToStore"); XMLAdapter intAdapter(i, asContent?0:"myInt", asElement); storer.Load(intAdapter); XMLAdapter doubleAdapter(d, asContent?0:"myDouble", asElement); storer.Load(doubleAdapter); XMLAdapter charAdapter(c, asContent?0:"myChar", asElement); storer.Load(charAdapter); XMLAdapter strAdapter(s, asContent?0:"myString", asElement); storer.Load(strAdapter); } }; class ArrayAdapterTestCase { protected: int *iarray; double *darray; char *carray; std::string *sarray; unsigned isize, dsize, csize, ssize; public: static const char * kind() {return "Array of Simple type Adapter";} template void Fill(T*& target, unsigned & targetsize, T* source, unsigned size) { target=new T[size]; targetsize = size; for (unsigned j = 0; j','"','b','c','&'}; std::string sArray[] = {"Hi,you", "HowAreYou?", "VeryWell,thanks,&you?"}; Fill(iarray,isize,iArray,sizeof(iArray)/sizeof(int)); Fill(darray,dsize,dArray,sizeof(dArray)/sizeof(double)); Fill(carray,csize,cArray,sizeof(cArray)/sizeof(char)); Fill(sarray,ssize,sArray,sizeof(sArray)/sizeof(std::string)); } ArrayAdapterTestCase() { int iArray[] = {0,0,0,0,0,0}; double dArray[] = {6.66,6.66,6.66,6.66,6.66,6.66}; char cArray[] = {'=','=','=','=','=','=','=','='}; std::string sArray[] = {"Empty1", "Empty2", "Empty3"}; Fill(iarray,isize,iArray,sizeof(iArray)/sizeof(int)); Fill(darray,dsize,dArray,sizeof(dArray)/sizeof(double)); Fill(carray,csize,cArray,sizeof(cArray)/sizeof(char)); Fill(sarray,ssize,sArray,sizeof(sArray)/sizeof(std::string)); } ~ArrayAdapterTestCase() { delete[] iarray; delete[] darray; delete[] carray; delete[] sarray; } bool DiferenceCause(const ArrayAdapterTestCase & other, std::string &context) const { bool areDifferent = false; std::stringstream out; for (unsigned j=0; j intAdapter(iarray, isize, asContent?0:"myInt", asElement); storer.Store(intAdapter); XMLArrayAdapter doubleAdapter(darray, dsize, asContent?0:"myDouble", asElement); storer.Store(doubleAdapter); XMLArrayAdapter charAdapter(carray, csize, asContent?0:"myChar", asElement); storer.Store(charAdapter); XMLArrayAdapter strAdapter(sarray, ssize, asContent?0:"myString", asElement); storer.Store(strAdapter); } void AdaptToLoad(Storage & storer, bool asContent, bool asElement) { CLAM_ASSERT(!(asContent && asElement), "Testing logic calling in AdaptToStore"); XMLArrayAdapter intAdapter(iarray, isize, asContent?0:"myInt", asElement); storer.Load(intAdapter); XMLArrayAdapter doubleAdapter(darray, dsize, asContent?0:"myDouble", asElement); storer.Load(doubleAdapter); XMLArrayAdapter charAdapter(carray, csize, asContent?0:"myChar", asElement); storer.Load(charAdapter); XMLArrayAdapter strAdapter(sarray, ssize, asContent?0:"myString", asElement); storer.Load(strAdapter); } }; /** * A Component that is a test case for testing IterableAdapters of * some bassic types. * This one is much like the SimpleAdapterTestCase but the * Store procedure use static adapters. */ class IterableAdapterTestCase : public ArrayAdapterTestCase { std::vector iv; std::vector dv; std::vector cv; std::vector sv; public: IterableAdapterTestCase(bool b) : ArrayAdapterTestCase(b) { CopyCArrays(); } IterableAdapterTestCase() : ArrayAdapterTestCase() { CopyCArrays(); } void CopyCArrays() { iv.assign(iarray, iarray+isize); dv.assign(darray, darray+dsize); cv.assign(carray, carray+csize); sv.assign(sarray, sarray+ssize); } static const char * kind() {return "XMLIterableAdapter";} void AdaptToStore(Storage & storer, bool asContent, bool asElement) { CLAM_ASSERT(!(asContent && asElement), "Testing logic calling in AdaptToStore"); std::string dummy; XMLAdapter separator(dummy, "Separator", true); XMLIterableAdapter > intAdapter(iv, "elemi", asContent?0:"myInt", asElement); storer.Store(intAdapter); if (asContent) storer.Store(separator); XMLIterableAdapter > doubleAdapter(dv, "elemd", asContent?0:"myDouble", asElement); storer.Store(doubleAdapter); if (asContent) storer.Store(separator); XMLIterableAdapter > charAdapter(cv, "elemc", asContent?0:"myChar", asElement); storer.Store(charAdapter); if (asContent) storer.Store(separator); XMLIterableAdapter > strAdapter(sv, "elems", asContent?0:"myString", asElement); storer.Store(strAdapter); } void AdaptToLoad(Storage & storer, bool asContent, bool asElement) { CLAM_ASSERT(!(asContent && asElement), "Testing logic calling in AdaptToLoad"); std::string dummy; XMLAdapter separator(dummy, "Separator", true); XMLIterableAdapter > intAdapter(iv, "elemi", asContent?0:"myInt", asElement); storer.Load(intAdapter); if (asContent) storer.Load(separator); XMLIterableAdapter > doubleAdapter(dv, "elemd", asContent?0:"myDouble", asElement); storer.Load(doubleAdapter); if (asContent) storer.Load(separator); XMLIterableAdapter > charAdapter(cv, "elemc", asContent?0:"myChar", asElement); storer.Load(charAdapter); if (asContent) storer.Load(separator); XMLIterableAdapter > strAdapter(sv, "elems", asContent?0:"myString", asElement); storer.Load(strAdapter); } bool DiferenceCause(const IterableAdapterTestCase & other, std::string &context) const { bool areDifferent = false; std::stringstream out; for (unsigned j=0; j myAdapter1(plain); store.Store(myAdapter1); XMLAdapter myAdapter2(attribute, "mySubItem"); store.Store(myAdapter2); XMLAdapter myAdapter3(element, "mySubItem", true); store.Store(myAdapter3); } virtual void LoadFrom (Storage & store) { XMLAdapter myAdapter1(plain); store.Load(myAdapter1); XMLAdapter myAdapter2(attribute, "mySubItem"); store.Load(myAdapter2); XMLAdapter myAdapter3(element, "mySubItem", true); store.Load(myAdapter3); } // Attributes private: std::string plain; std::string attribute; std::string element; }; class ComponentAdapterTestCase { public: ComponentAdapterTestCase(char c) : mComponent(c) { } ComponentAdapterTestCase(char c, bool b) : mComponent(c) { mComponent.modify(); } static const char * kind() {return "XMLComponentAdapter";} void AdaptToStore(Storage & storer, bool asContent, bool asElement) const { CLAM_ASSERT(!(asContent && asElement), "Testing logic calling in AdaptToStore"); CLAM_ASSERT(asContent || asElement, "Attributes not aplicable for XMLComponentAdapters"); XMLComponentAdapter adapter(mComponent, asContent?0:"AsElement", asElement); storer.Store(adapter); } void AdaptToLoad(Storage & storer, bool asContent, bool asElement) { CLAM_ASSERT(!(asContent && asElement), "Testing logic calling in AdaptToLoad"); CLAM_ASSERT(asContent || asElement, "Attributes not aplicable for XMLComponentAdapters"); XMLComponentAdapter adapter(mComponent, asContent?0:"AsElement", asElement); storer.Load(adapter); } bool DiferenceCause(const ComponentAdapterTestCase & other, std::string &context) const { if (mComponent==other.mComponent) return false; std::ostringstream out; out << "Found: " << std::endl; mComponent.print(out); out << "Expected: " << std::endl; other.mComponent.print(out); context = out.str(); return true; } // Attributes private: ComponentAdapterTestHelper mComponent; }; class ComponentAdaptersTester : public Component { public: ComponentAdaptersTester() { mId="ComponentAdapter"; } const char * GetClassName() const { return "ComponentAdaptersTester"; } void StoreOn(Storage & storer) const { ComponentAdapterTestCase a('C'), b('E'); a.AdaptToStore(storer,true,false); // Content b.AdaptToStore(storer,false,true); // Element } void LoadFrom(Storage & storer) { { ComponentAdapterTestCase a('C',false), b('C'); a.AdaptToLoad(storer,true,false); // Content std::string context("Loading Content "+mId); bool failed = a.DiferenceCause(b,context); CLAM_ASSERT(!failed, context.c_str()); } { ComponentAdapterTestCase a('E',false), b('E'); a.AdaptToLoad(storer,false,true); // Element std::string context("Loading Element "+mId); bool failed = a.DiferenceCause(b,context); CLAM_ASSERT(!failed, context.c_str()); } } private: std::string mId; }; /** * A Component having only one parameter */ class MyComponent : public CLAM::Component { std::string mTag; public: MyComponent() {mTag="DefaultContent";}; MyComponent(const MyComponent &c) {mTag=c.mTag;}; MyComponent(std::string tag) {mTag=tag;}; const char * GetClassName() const { return "MyComponent"; } virtual ~MyComponent() {}; void StoreOn(CLAM::Storage & s) const { CLAM::XMLAdapter adapt(mTag); s.Store(adapt); } void LoadFrom(CLAM::Storage & s) { std::string text; CLAM::XMLAdapter adapt(mTag); s.Load(adapt); } }; class XmlAdaptersTest : public CppUnit::TestFixture { public: CPPUNIT_TEST_SUITE (CLAMTest::XmlAdaptersTest); CPPUNIT_TEST (testXmlAdapter); CPPUNIT_TEST (testXmlArrayAdapter); CPPUNIT_TEST (testXmlIterableAdapter); CPPUNIT_TEST (testXmlComponentAdapter); CPPUNIT_TEST (testXmlComponentArray); CPPUNIT_TEST (testXmlComponentList); CPPUNIT_TEST_SUITE_END(); private: /** * Tests the XMLAdapter class */ void testXmlAdapter() { GenericAdaptersTester tester; bool match = XMLInputOutputMatches(tester,__FILE__"Simple.xml"); CLAM_ASSERT(match, "Store/Load mismatch using basic types adapters"); } /** * Tests the XMLArrayAdapter class */ void testXmlArrayAdapter() { GenericAdaptersTester tester; bool match = XMLInputOutputMatches(tester,__FILE__"Array.xml"); CLAM_ASSERT(match, "Store/Load mismatch using basic type arrays adapters"); } /** * Tests the XMLIterableAdapter class */ void testXmlIterableAdapter() { GenericAdaptersTester tester; bool match = XMLInputOutputMatches(tester,__FILE__"Array.xml"); CLAM_ASSERT(match, "Store/Load mismatch using basic type iterable adapters"); } /** * Tests the XMLComponentAdapter class */ void testXmlComponentAdapter() { ComponentAdaptersTester tester; bool match = XMLInputOutputMatches(tester,__FILE__"Component.xml"); CLAM_ASSERT(match, "Store/Load mismatch using component adapters"); } void testXmlComponentArray() { CLAM::Array a; a.AddElem(MyComponent("One")); a.AddElem(MyComponent("Two")); a.AddElem(MyComponent("Three")); a.AddElem(MyComponent("Four")); bool match = XMLInputOutputMatches(a,__FILE__"ComponentArray.xml"); CLAM_ASSERT(match, "Store/Load mismatch using array of components"); } void testXmlComponentList() { CLAM::List a; a.AddElem(MyComponent("One")); a.AddElem(MyComponent("Two")); a.AddElem(MyComponent("Three")); a.AddElem(MyComponent("Four")); bool match = XMLInputOutputMatches(a,__FILE__"ComponentListy.xml"); CLAM_ASSERT(match, "Store/Load mismatch using list of components"); } }; } clam-1.4.0/test/UnitTests/XmlTests/XercesDomReadingContextTest.cxx0000644000000000000000000006240611037400122023744 0ustar rootroot#ifdef USE_XERCES #include #include "cppUnitHelper.hxx" #include "XmlMockUpObjects.hxx" #include "Component.hxx" // CLAM #include #include "XercesDomWriter.hxx" // CLAM #include "XercesDomReader.hxx" // CLAM #include "XercesInitializer.hxx" // CLAM #include "XercesDomReadingContext.hxx" // CLAM #include #include #include #include #include #include /* TOTEST: - A comment doesn't break content - Any non-comment node does break content - Spaces at the begining of content are eaten - Attributes support */ namespace CLAM { namespace Test { class XercesDomReadingContextTest; CPPUNIT_TEST_SUITE_REGISTRATION( XercesDomReadingContextTest ); class XercesDomReadingContextTest : public CppUnit::TestCase { CPPUNIT_TEST_SUITE( XercesDomReadingContextTest ); CPPUNIT_TEST(testFetchContent_withASingleWordContent); CPPUNIT_TEST(testFetchContent_withTwoJointContents); CPPUNIT_TEST(testFetchContent_withTwoContentsSeparatedByElement); CPPUNIT_TEST(testFetchContent_withTwoContentsSeparatedByComment); CPPUNIT_TEST(testFetchContent_withNoNode); CPPUNIT_TEST(testFetchContent_withElementFirst); CPPUNIT_TEST(testContentLeft_withNoNode_returnsFalse); CPPUNIT_TEST(testContentLeft_withNonSpaceReturnsTrue); CPPUNIT_TEST(testContentLeft_withStartingSpacesAndNonSpace_chopsAndReturnsTrue); CPPUNIT_TEST(testContentLeft_withOnlySpaces_chopsAndReturnsFalse); CPPUNIT_TEST(testFindElement_withThatElementFirst); CPPUNIT_TEST(testFindElement_withWrongNameFails); CPPUNIT_TEST(testFindElement_withCommentBefore); CPPUNIT_TEST(testFindElement_withNoElement); CPPUNIT_TEST(testFindElement_withTextFirst); CPPUNIT_TEST(testFindElement_withReadedTextFirst); CPPUNIT_TEST(testFindElement_withHalfReadedTextFirst); CPPUNIT_TEST(testFindElement_withSpacesToReadFirst); CPPUNIT_TEST(testFindElement_withStillNonElement_asserts); CPPUNIT_TEST(testFetchElement_withThatElementFirst); CPPUNIT_TEST(testFetchElement_withSecondElementFirst); CPPUNIT_TEST(testFetchElement_withTextFirst); CPPUNIT_TEST(testFetchElement_withNoElement); CPPUNIT_TEST(testFetchElement_withADifferentName); CPPUNIT_TEST(testFetchElement_withANonElementNode); CPPUNIT_TEST(testFetchContent_afterElement); CPPUNIT_TEST(testFetchContent_whenSecondElement); CPPUNIT_TEST(testFetchContent_afterElementWithSpaces); CPPUNIT_TEST(testReleaseContext_atRootReturnsNull); CPPUNIT_TEST(testReleaseContext_whenIsChildContext); CPPUNIT_TEST(testRecursiveConstructor_initializesTheContext); CPPUNIT_TEST(testReleaseContext_whenContentLeft); CPPUNIT_TEST(testReleaseContext_whenElementLeft); CPPUNIT_TEST(testExtractAttribute_whenNone); CPPUNIT_TEST(testExtractAttribute_whenPresent); CPPUNIT_TEST(testExtractAttribute_withDifferentAttributeName); CPPUNIT_TEST(testGetPath); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { XercesInitializer::require(); mTargetStream.str(""); xercesc::DOMImplementation * imp = xercesc::DOMImplementation::getImplementation(); mDocument = imp->createDocument( U("2003-04.clam05.iua.mtg.upf.es"), // root element namespace URI. U("TestDoc"), // root element name 0 // document type object (DTD). ); } /// Common clean up, executed after each test method void tearDown() { mDocument->release(); } private: std::stringstream mTargetStream; xercesc::DOMDocument * mDocument; void testFetchContent_withASingleWordContent() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMText * domContent = mDocument->createTextNode(U("Content")); contextElement->appendChild(domContent); XercesDomReadingContext context(contextElement); std::string content; std::getline(context.reachableContent(), content); CPPUNIT_ASSERT_EQUAL(std::string("Content"),content); } void testFetchContent_withTwoJointContents() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMText * domContent1 = mDocument->createTextNode(U("Content1")); xercesc::DOMText * domContent2 = mDocument->createTextNode(U("Content2")); contextElement->appendChild(domContent1); contextElement->appendChild(domContent2); XercesDomReadingContext context(contextElement); std::string content; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(std::string("Content1Content2"),content); } void testFetchContent_withTwoContentsSeparatedByElement() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMText * domContent1 = mDocument->createTextNode(U("Content1")); xercesc::DOMElement * separator = mDocument->createElement(U("Separator")); xercesc::DOMText * domContent2 = mDocument->createTextNode(U("Content2")); contextElement->appendChild(domContent1); contextElement->appendChild(separator); contextElement->appendChild(domContent2); XercesDomReadingContext context(contextElement); std::string content; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(std::string("Content1"),content); } void testFetchContent_withTwoContentsSeparatedByComment() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMText * domContent1 = mDocument->createTextNode(U("Content1")); xercesc::DOMComment * separator = mDocument->createComment(U("Separator")); xercesc::DOMText * domContent2 = mDocument->createTextNode(U("Content2")); contextElement->appendChild(domContent1); contextElement->appendChild(separator); contextElement->appendChild(domContent2); XercesDomReadingContext context(contextElement); std::string content; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(std::string("Content1Content2"),content); } void testFetchContent_withNoNode() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); XercesDomReadingContext context(contextElement); std::string content="rubbish"; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(true,stream.fail()); CPPUNIT_ASSERT_EQUAL(std::string(""),content); } void testFetchContent_withElementFirst() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMElement * unexpectedElement = mDocument->createElement(U("UnexpectedElement")); xercesc::DOMText * domContent = mDocument->createTextNode(U("Content")); contextElement->appendChild(unexpectedElement); contextElement->appendChild(domContent); XercesDomReadingContext context(contextElement); std::string content="rubbish"; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT(stream.fail()); CPPUNIT_ASSERT_EQUAL(std::string(""),content); } void testContentLeft_withNoNode_returnsFalse() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); XercesDomReadingContext context(contextElement); std::string content="rubbish"; bool charactersLeft = context.contentLeft(); CPPUNIT_ASSERT(!charactersLeft); } void testContentLeft_withNonSpaceReturnsTrue() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMText * domContent = mDocument->createTextNode(U("Content")); contextElement->appendChild(domContent); XercesDomReadingContext context(contextElement); bool charactersLeft = context.contentLeft(); CPPUNIT_ASSERT(charactersLeft); std::string content="rubbish"; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(std::string("Content"),content); } void testContentLeft_withStartingSpacesAndNonSpace_chopsAndReturnsTrue() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMText * domContent = mDocument->createTextNode(U(" \t \n Content")); contextElement->appendChild(domContent); XercesDomReadingContext context(contextElement); bool charactersLeft = context.contentLeft(); CPPUNIT_ASSERT(charactersLeft); std::string content="rubbish"; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(std::string("Content"),content); } void testContentLeft_withOnlySpaces_chopsAndReturnsFalse() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMText * domContent = mDocument->createTextNode(U(" \t \n ")); contextElement->appendChild(domContent); XercesDomReadingContext context(contextElement); bool charactersLeft = context.contentLeft(); CPPUNIT_ASSERT(!charactersLeft); std::string content="rubbish"; std::istream & stream = context.reachableContent(); std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(std::string(""),content); } void testFindElement_withThatElementFirst() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); contextElement->appendChild(domElement); XercesDomReadingContext context(contextElement); bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(foundElement); } void testFindElement_withWrongNameFails() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMElement * domElement1 = mDocument->createElement(U("Wrong")); xercesc::DOMElement * domElement2 = mDocument->createElement(U("Element")); contextElement->appendChild(domElement1); contextElement->appendChild(domElement2); XercesDomReadingContext context(contextElement); bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(!foundElement); } void testFindElement_withCommentBefore() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMComment * separator = mDocument->createComment(U("Separator")); xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); contextElement->appendChild(separator); contextElement->appendChild(domElement); XercesDomReadingContext context(contextElement); bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(foundElement); } void testFindElement_withNoElement() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); XercesDomReadingContext context(contextElement); bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(!foundElement); } void testFindElement_withTextFirst() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMText * domContent = mDocument->createTextNode(U("ContentLeft")); xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); contextElement->appendChild(domContent); contextElement->appendChild(domElement); XercesDomReadingContext context(contextElement); bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(!foundElement); } void testFindElement_withReadedTextFirst() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMText * domContent = mDocument->createTextNode(U("ReadingContent")); xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); contextElement->appendChild(domContent); contextElement->appendChild(domElement); XercesDomReadingContext context(contextElement); std::string content; context.reachableContent() >> content; bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(foundElement); CPPUNIT_ASSERT_EQUAL(std::string("ReadingContent"), content); } void testFindElement_withHalfReadedTextFirst() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMText * domContent = mDocument->createTextNode(U("Reading Content")); xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); contextElement->appendChild(domContent); contextElement->appendChild(domElement); XercesDomReadingContext context(contextElement); std::string content; context.reachableContent() >> content; bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(!foundElement); CPPUNIT_ASSERT_EQUAL(std::string("Reading"), content); } void testFindElement_withSpacesToReadFirst() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMText * domContent = mDocument->createTextNode(U(" \n \t \t \r ")); xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); contextElement->appendChild(domContent); contextElement->appendChild(domElement); XercesDomReadingContext context(contextElement); bool foundElement = context.findElement("Element"); CPPUNIT_ASSERT(foundElement); } void testFindElement_withStillNonElement_asserts() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMProcessingInstruction * domProcessingInstruction = mDocument->createProcessingInstruction(U("ProcessingInstruction"),U("Content")); contextElement->appendChild(domProcessingInstruction); XercesDomReadingContext context(contextElement); try { context.findElement("Element"); CPPUNIT_FAIL("Should have failed an assertion"); } catch (ErrAssertionFailed & e) { CPPUNIT_ASSERT_EQUAL( std::string("Can't change the context to a non element node"), std::string(e.what())); } } void testFetchElement_withThatElementFirst() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); contextElement->appendChild(domElement); XercesDomReadingContext context(contextElement); xercesc::DOMElement * foundElement = context.fetchElement("Element"); CPPUNIT_ASSERT_EQUAL(domElement, foundElement); } void testFetchElement_withSecondElementFirst() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMElement * domElement1 = mDocument->createElement(U("Element1")); xercesc::DOMElement * domElement2 = mDocument->createElement(U("Element2")); contextElement->appendChild(domElement1); contextElement->appendChild(domElement2); XercesDomReadingContext context(contextElement); xercesc::DOMElement * foundElement1 = context.fetchElement("Element1"); xercesc::DOMElement * foundElement2 = context.fetchElement("Element2"); CPPUNIT_ASSERT_EQUAL(domElement2, foundElement2); CPPUNIT_ASSERT_EQUAL(domElement1, foundElement1); } void testFetchElement_withTextFirst() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMText * domContent = mDocument->createTextNode(U("ContentLeft")); xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); contextElement->appendChild(domContent); contextElement->appendChild(domElement); XercesDomReadingContext context(contextElement); try { xercesc::DOMElement * foundElement = context.fetchElement("Element"); CPPUNIT_FAIL("Should have failed an assertion"); foundElement = 0; // To stop warnings } catch (ErrAssertionFailed & e) { CPPUNIT_ASSERT_EQUAL( std::string("Fetching element with content left"), std::string(e.what())); } } void testFetchElement_withNoElement() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); contextElement->appendChild(domElement); XercesDomReadingContext context(contextElement); xercesc::DOMElement * foundElement1 = context.fetchElement("Element"); try { xercesc::DOMElement * foundElement2 = context.fetchElement("Element"); CPPUNIT_FAIL("Should have failed an assertion"); foundElement2 = 0; // To stop warnings } catch (ErrAssertionFailed & e) { CPPUNIT_ASSERT_EQUAL( std::string("Accessing beyond DOM nodes"), std::string(e.what())); } foundElement1 = 0; // To stop warnings } void testFetchElement_withADifferentName() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); contextElement->appendChild(domElement); XercesDomReadingContext context(contextElement); try { xercesc::DOMElement * foundElement = context.fetchElement("WrongElement"); CPPUNIT_FAIL("Should have failed an assertion"); foundElement = 0; // To stop warnings } catch (ErrAssertionFailed & e) { CPPUNIT_ASSERT_EQUAL( std::string("XML element name should be the one expected"), std::string(e.what())); } } void testFetchElement_withANonElementNode() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMProcessingInstruction * domProcessingInstruction = mDocument->createProcessingInstruction(U("ProcessingInstruction"),U("Content")); contextElement->appendChild(domProcessingInstruction); XercesDomReadingContext context(contextElement); try { xercesc::DOMElement * foundElement = context.fetchElement("Element"); CPPUNIT_FAIL("Should have failed an assertion"); foundElement = 0; // To stop warnings } catch (ErrAssertionFailed & e) { CPPUNIT_ASSERT_EQUAL( std::string("Can't change the context to a non element node"), std::string(e.what())); } } void testFetchContent_afterElement() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMText * domContent1 = mDocument->createTextNode(U("Content1")); xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); xercesc::DOMText * domContent2 = mDocument->createTextNode(U("Content2")); contextElement->appendChild(domContent1); contextElement->appendChild(domElement); contextElement->appendChild(domContent2); XercesDomReadingContext context(contextElement); std::string content1="rubbish"; std::getline(context.reachableContent(), content1); xercesc::DOMElement * foundElement = context.fetchElement("Element"); std::string content2="rubbish"; std::getline(context.reachableContent(), content2); CPPUNIT_ASSERT_EQUAL(std::string("Content2"),content2); foundElement = 0; // To stop warnings } void testFetchContent_whenSecondElement() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMElement * domElement1 = mDocument->createElement(U("Element1")); xercesc::DOMElement * domElement2 = mDocument->createElement(U("Element2")); contextElement->appendChild(domElement1); contextElement->appendChild(domElement2); XercesDomReadingContext context(contextElement); xercesc::DOMElement * foundElement = context.fetchElement("Element1"); std::istream & stream = context.reachableContent(); std::string content="rubbish"; std::getline(stream, content); CPPUNIT_ASSERT_EQUAL(true,stream.fail()); CPPUNIT_ASSERT_EQUAL(std::string(""),content); foundElement = 0; // To stop warnings } void testFetchContent_afterElementWithSpaces() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); xercesc::DOMText * domContent = mDocument->createTextNode(U(" Content")); contextElement->appendChild(domElement); contextElement->appendChild(domContent); XercesDomReadingContext context(contextElement); xercesc::DOMElement * foundElement = context.fetchElement("Element"); std::string content2="rubbish"; std::getline(context.reachableContent(), content2); CPPUNIT_ASSERT_EQUAL(std::string("Content"),content2); foundElement = 0; // To stop warnings } void testReleaseContext_atRootReturnsNull() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); XercesDomReadingContext context(contextElement); XercesDomReadingContext * previous = context.release(); CPPUNIT_ASSERT_EQUAL((XercesDomReadingContext*)0, previous); } void testReleaseContext_whenIsChildContext() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); contextElement->appendChild(domElement); XercesDomReadingContext context1(contextElement); XercesDomReadingContext context2(&context1,"Element"); XercesDomReadingContext * previous = context2.release(); CPPUNIT_ASSERT_EQUAL(&context1, previous); } void testRecursiveConstructor_initializesTheContext() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMElement * outerElement = mDocument->createElement(U("Element")); xercesc::DOMElement * innerElement = mDocument->createElement(U("InnerElement")); contextElement->appendChild(outerElement); outerElement->appendChild(innerElement); XercesDomReadingContext contextRoot(contextElement); XercesDomReadingContext contextInner(&contextRoot,"Element"); xercesc::DOMElement * foundElement = contextInner.fetchElement("InnerElement"); CPPUNIT_ASSERT_EQUAL(innerElement, foundElement); foundElement = 0; // To stop warnings } void testReleaseContext_whenContentLeft() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMText * domContent = mDocument->createTextNode(U("Offending input\none line more")); contextElement->appendChild(domContent); XercesDomReadingContext context(contextElement); context.release(); std::list errors = context.errors(); std::string result; for (std::list::iterator it=errors.begin(); it!=errors.end(); it++) result+= *it + '\n'; CPPUNIT_ASSERT_EQUAL(std::string( "Unexpected content: 'Offending input\none line more' at position /ContextElement\n"), result ); } void testReleaseContext_whenElementLeft() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMElement * domElement = mDocument->createElement(U("Element")); xercesc::DOMElement * unparsedElement = mDocument->createElement(U("Offender")); contextElement->appendChild(domElement); contextElement->appendChild(unparsedElement); XercesDomReadingContext context(contextElement); context.fetchElement("Element"); context.release(); std::list errors = context.errors(); std::string result; for (std::list::iterator it=errors.begin(); it!=errors.end(); it++) result+= *it + '\n'; CPPUNIT_ASSERT_EQUAL(std::string( "Unexpected Element: 'Offender' at position /ContextElement\n"), result ); } void testRelease_whenANonElementAndNonContentNodeLeft() { // TODO } void testExtractAttribute_whenNone() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); XercesDomReadingContext context(contextElement); std::stringstream stream; bool result = context.extractAttribute("Unexistent", stream); CPPUNIT_ASSERT_MESSAGE("Should have been false",!result); } void testExtractAttribute_whenPresent() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMAttr * domAttribute = mDocument->createAttribute(U("Attribute")); contextElement->setAttribute(U("Attribute"),U("AttributeValue")); XercesDomReadingContext context(contextElement); std::stringstream stream; bool result = context.extractAttribute("Attribute", stream); CPPUNIT_ASSERT_MESSAGE("Should have been true",result); std::string extractedValue; stream >> extractedValue; CPPUNIT_ASSERT_EQUAL(std::string("AttributeValue"),extractedValue); domAttribute = 0; // To stop } void testExtractAttribute_withDifferentAttributeName() { xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMAttr * domAttribute = mDocument->createAttribute(U("Attribute")); contextElement->setAttribute(U("Attribute"),U("AttributeValue")); XercesDomReadingContext context(contextElement); std::stringstream stream; bool result = context.extractAttribute("WrongAttribute", stream); CPPUNIT_ASSERT_MESSAGE("Should have been false",!result); domAttribute = 0; // To stop } void testGetPath() { XercesDomReader reader; xercesc::DOMElement * contextElement = mDocument->createElement(U("ContextElement")); xercesc::DOMElement * element1 = mDocument->createElement(U("Element1")); xercesc::DOMElement * element2 = mDocument->createElement(U("Element2")); xercesc::DOMElement * element3 = mDocument->createElement(U("Element3")); contextElement->appendChild(element1); element1->appendChild(element2); element2->appendChild(element3); XercesDomReadingContext context0(contextElement); XercesDomReadingContext context1(&context0,"Element1"); XercesDomReadingContext context2(&context1,"Element2"); XercesDomReadingContext context3(&context2,"Element3"); std::string path = context3.getPath(); CPPUNIT_ASSERT_EQUAL(std::string("/ContextElement/Element1/Element2/Element3"),path); } }; } // namespace Test } // namespace Cuidado #endif // USE_XERCE clam-1.4.0/test/UnitTests/XmlTests/XercesDom2ClamObjectsTest.cxx0000644000000000000000000003235411165016735023314 0ustar rootroot#ifdef USE_XERCES #include #include "cppUnitHelper.hxx" #include "XMLStorage.hxx" // CLAM #include "XmlMockUpObjects.hxx" #include /* TOTEST: - Return values on error conditions - Recursive behaviour for text components - Recursive behaviour for element components */ namespace CLAM { namespace Test { class XercesDomToClamObjectsTest; CPPUNIT_TEST_SUITE_REGISTRATION( XercesDomToClamObjectsTest ); class XercesDomToClamObjectsTest : public CppUnit::TestCase { CPPUNIT_TEST_SUITE( XercesDomToClamObjectsTest ); CPPUNIT_TEST(testLoadingAWordOnBasicAsContent); CPPUNIT_TEST(testLoadingTwoWordsOnTwoBasicsAsContent); CPPUNIT_TEST(testLoadingOneWordsOnTwoBasicsAsContent_secondLoadFails); CPPUNIT_TEST(testEmptyElement_WithRightLabel); CPPUNIT_TEST(testEmptyElement_WithWrongLabel); CPPUNIT_TEST(testLoadingElementContent); CPPUNIT_TEST(testLoadingContentAfterElement); CPPUNIT_TEST(testLoadingSubobjects); CPPUNIT_TEST(testLoadingSubobjects_whenComponentIsContent); CPPUNIT_TEST(testForErrors_UnexpectedElementOnRoot); CPPUNIT_TEST(testForErrors_UnexpectedContentOnRoot); CPPUNIT_TEST(testForErrors_UnexpectedElementOnInner); CPPUNIT_TEST(testForErrors_UnexpectedContentOnInner); CPPUNIT_TEST(testForErrors_withXmlParseErrors); CPPUNIT_TEST(testLoading_OnAInnerSelection); CPPUNIT_TEST(testAppendToDocumentUsingPrimitives); CPPUNIT_TEST(testAppendToDocument); CPPUNIT_TEST(testRestoreFromFragmentUsingPrimitives); CPPUNIT_TEST(testRestoreFromFragment); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { mTargetStream.str(""); } /// Common clean up, executed after each test method void tearDown() { } private: void assertComponentsLoaded(const std::string & expected, CompositeOfXmlables & toLoad, std::istream & xml) { XMLStorage loader; loader.Read(xml); loader.RestoreObject(toLoad); CPPUNIT_ASSERT_EQUAL(expected, toLoad.childStructureTrace(0)); } void assertErrorGiven(const std::string & expected, CompositeOfXmlables & toLoad, std::istream & xml, const std::string & parsed="") { XMLStorage loader; try { loader.Read(xml); loader.RestoreObject(toLoad); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::XmlStorageErr & err) { CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } CPPUNIT_ASSERT_EQUAL(parsed, toLoad.childStructureTrace(0)); } std::stringstream mTargetStream; void testLoadingAWordOnBasicAsContent() { std::istringstream xml( "" "Content" "" ); CompositeOfXmlables toLoad; XmlMockUpBasic basic; basic.setContent("PreviousValue"); toLoad.add(basic); std::string expected= "B'Content'\n"; assertComponentsLoaded(expected, toLoad, xml); } void testLoadingTwoWordsOnTwoBasicsAsContent() { std::istringstream xml( "" "Content1 Content2" "" ); CompositeOfXmlables toLoad; XmlMockUpBasic basic1; basic1.setContent("PreviousValue1"); XmlMockUpBasic basic2; basic2.setContent("PreviousValue2"); toLoad.add(basic1); toLoad.add(basic2); std::string expected= "B'Content1'\n" "B'Content2'\n"; assertComponentsLoaded(expected, toLoad, xml); } void testLoadingOneWordsOnTwoBasicsAsContent_secondLoadFails() { std::istringstream xml( "" "Content1" "" ); CompositeOfXmlables toLoad; XmlMockUpBasic basic1; basic1.setContent("PreviousValue1"); XmlMockUpBasic basic2; basic2.setContent("PreviousValue2"); toLoad.add(basic1); toLoad.add(basic2); std::string expected= "B'Content1'\n" "B''[unloaded]\n"; assertComponentsLoaded(expected, toLoad, xml); } void testEmptyElement_WithRightLabel() { std::istringstream xml( "" "" "" ); CompositeOfXmlables toLoad; XmlMockUpBasic basic("Element",true); toLoad.add(basic); std::string expected= "B''\n"; assertComponentsLoaded(expected, toLoad, xml); } void testEmptyElement_WithWrongLabel() { std::istringstream xml( "" "" "" ); CompositeOfXmlables toLoad; XmlMockUpBasic basic("Element",true); basic.setContent("PreviousValue"); XmlMockUpBasic basic2("Other",true); basic2.setContent("PreviousOtherValue"); toLoad.add(basic); toLoad.add(basic2); std::string expected= "B'PreviousValue'[unloaded]\n" "B''\n"; assertComponentsLoaded(expected, toLoad, xml); } void testLoadingElementContent() { std::istringstream xml( "" "ElementContent" "" ); CompositeOfXmlables toLoad; XmlMockUpComponent component("Element",true); component.setContent("PeviousValue1"); toLoad.add(component); std::string expected= "C'ElementContent'\n{\n}\n"; assertComponentsLoaded(expected, toLoad, xml); } void testLoadingContentAfterElement() { std::istringstream xml( "" "" "AfterElementContent" "" ); CompositeOfXmlables toLoad; XmlMockUpBasic basic1("Element",true); basic1.setContent("PreviousValue1"); XmlMockUpBasic basic2; basic2.setContent("PreviousValue2"); toLoad.add(basic1); toLoad.add(basic2); std::string expected= "B''\n" "B'AfterElementContent'\n"; assertComponentsLoaded(expected, toLoad, xml); } void testLoadingSubobjects() { std::istringstream xml( "" "" "" "AfterElementContent" "" "" ); CompositeOfXmlables toLoad; XmlMockUpComponent component("Element",true); component.setContent("PreviousElementContent"); XmlMockUpBasic basic1("SubElement",true); basic1.setContent("PreviousValue1"); XmlMockUpBasic basic2; basic2.setContent("PreviousValue2"); component.add(basic1); component.add(basic2); toLoad.add(component); std::string expected= "C''\n" "{\n" ".B''\n" ".B'AfterElementContent'\n" "}\n"; assertComponentsLoaded(expected, toLoad, xml); } void testLoadingSubobjects_whenComponentIsContent() { std::istringstream xml( "" "" "AfterElementContent" "" ); CompositeOfXmlables toLoad; XmlMockUpComponent component; component.setContent("PreviousElementContent"); XmlMockUpBasic basic1("SubElement",true); basic1.setContent("PreviousValue1"); XmlMockUpBasic basic2; basic2.setContent("PreviousValue2"); component.add(basic1); component.add(basic2); toLoad.add(component); std::string expected= "C''[unloaded]\n" // because the component content is empty "{\n" ".B''\n" ".B'AfterElementContent'\n" "}\n"; assertComponentsLoaded(expected, toLoad, xml); } void testForErrors_UnexpectedElementOnRoot() { std::istringstream xml( "" "" "" "" ); CompositeOfXmlables toLoad; std::string expected= "Unexpected Element: 'Element' at position /Doc\n"; std::string parsed=""; assertErrorGiven(expected, toLoad, xml, parsed); } void testForErrors_UnexpectedContentOnRoot() { std::istringstream xml( "" "Unexpected content" "" ); CompositeOfXmlables toLoad; std::string expected= "Unexpected content: 'Unexpected content' at position /Doc\n"; std::string parsed= ""; assertErrorGiven(expected, toLoad, xml, parsed); } void testForErrors_UnexpectedElementOnInner() { std::istringstream xml( "" "" "" "" "" ); CompositeOfXmlables toLoad; XmlMockUpComponent component("Element",true); component.setContent("PreviousElementContent"); toLoad.add(component); std::string expected= "Unexpected Element: 'UnExpectedSubElement' at position /Doc/Element\n"; std::string parsed= "C''\n" "{\n" "}\n"; assertErrorGiven(expected, toLoad, xml, parsed); } void testForErrors_UnexpectedContentOnInner() { std::istringstream xml( "" "" "ParsedWord Unexpected Content" "" "" ); CompositeOfXmlables toLoad; XmlMockUpComponent component("Element",true); component.setContent("PreviousElementContent"); toLoad.add(component); std::string expected= "Unexpected content: 'Unexpected Content' at position /Doc/Element\n"; std::string parsed= "C'ParsedWord'\n" "{\n" "}\n"; assertErrorGiven(expected, toLoad, xml, parsed); } void testForErrors_withXmlParseErrors() { std::istringstream xml( "" "" "" ); CompositeOfXmlables toLoad; std::string expected= "\nXML Parser Errors:\n" "Fatal Error at file CLAMParser, line 1, col 8:\n" "Expected end of tag 'Doc'\n"; std::string parsed= ""; assertErrorGiven(expected, toLoad, xml, parsed); } void testLoading_OnAInnerSelection() { std::istringstream xml( "" "" "Content" "" "" ); CompositeOfXmlables toLoad; XmlMockUpComponent component("SubElement",true); component.setContent("PreviousElementContent"); toLoad.add(component); std::string expected= "C'Content'\n" "{\n" "}\n"; XMLStorage loader; loader.Read(xml); loader.Select("/Doc/Element"); loader.RestoreObject(toLoad); CPPUNIT_ASSERT_EQUAL(expected, toLoad.childStructureTrace(0)); } // TODO; On this suite? void testAppendToDocumentUsingPrimitives() { std::istringstream xml( "" "" "" "OldElementContent" "" "" ); CompositeOfXmlables toAppend; XmlMockUpComponent component("Element",true); XmlMockUpBasic basic("SubElement",true); basic.setContent("SubElementContent"); component.add(basic); XmlMockUpComponent component2("Element2",true); toAppend.add(component); toAppend.add(component2); XmlStorage storage; storage.Read(xml); storage.Select("Recipient"); storage.DumpObject(toAppend); std::ostringstream os; storage.WriteDocument(os); std::string expected = "" "" "" "" "OldElementContent" "" "" "SubElementContent" "" "" "" "" ""; CPPUNIT_ASSERT_EQUAL(expected,os.str()); } void testAppendToDocument() { { std::ofstream os("deleteme.xml"); os << "" "" "" "OldElementContent" "" "" ; } CompositeOfXmlables toAppend; XmlMockUpComponent component("Element",true); XmlMockUpBasic basic("SubElement",true); basic.setContent("SubElementContent"); component.add(basic); XmlMockUpComponent component2("Element2",true); toAppend.add(component); toAppend.add(component2); XmlStorage::AppendToDocument(toAppend, "/Doc/Recipient", "deleteme.xml"); std::string expected = "" "" "" "" "OldElementContent" "" "" "SubElementContent" "" "" "" "" ""; std::string result; std::ifstream is("deleteme.xml"); for (char buffer[255]; is.get(buffer,255,'\0');) result += buffer; CPPUNIT_ASSERT_EQUAL(expected,result); remove("deleteme.xml"); } void testRestoreFromFragmentUsingPrimitives() { std::istringstream xml( "" "" "" "" "SubElementContent" "" "" "" "Element2Content" "" "" "" "" ); CompositeOfXmlables toExtract; XmlMockUpComponent component("Element",true); component.setContent("PreviousElementContent"); XmlMockUpBasic basic("SubElement",true); basic.setContent("PreviousSubElementContent"); XmlMockUpComponent component2("Element2",true); component.setContent("PreviousElement2Content"); component.add(basic); toExtract.add(component); toExtract.add(component2); XmlStorage storage; storage.Read(xml); storage.Select("Recipient"); storage.RestoreObject(toExtract); std::string expected = "C''\n" "{\n" ".B'SubElementContent'\n" "}\n" "C'Element2Content'\n" "{\n" "}\n"; CPPUNIT_ASSERT_EQUAL(expected, toExtract.childStructureTrace(0)); } void testRestoreFromFragment() { std::istringstream xml( "" "" "" "" "SubElementContent" "" "" "" "Element2Content" "" "" "" "" ); CompositeOfXmlables toExtract; XmlMockUpComponent component("Element",true); component.setContent("PreviousElementContent"); XmlMockUpBasic basic("SubElement",true); basic.setContent("PreviousSubElementContent"); XmlMockUpComponent component2("Element2",true); component.setContent("PreviousElement2Content"); component.add(basic); toExtract.add(component); toExtract.add(component2); XmlStorage::RestoreFromFragment(toExtract,"Recipient",xml); std::string expected = "C''\n" "{\n" ".B'SubElementContent'\n" "}\n" "C'Element2Content'\n" "{\n" "}\n"; CPPUNIT_ASSERT_EQUAL(expected, toExtract.childStructureTrace(0)); } }; } // namespace Test } // namespace Cuidado #endif // USE_XERCES clam-1.4.0/test/UnitTests/XmlTests/XercesDomDocumentHandlerTest.cxx0000644000000000000000000002516011160506752024113 0ustar rootroot#ifdef USE_XERCES #include #include "cppUnitHelper.hxx" #include "XercesDomDocumentHandler.hxx" // CLAM #include "XercesInitializer.hxx" // CLAM #include #include #include "XercesEncodings.hxx" // CLAM #include // TODO: Get the read errors namespace xercesc = XERCES_CPP_NAMESPACE; namespace CLAM { namespace Test { class XercesDomDocumentHandlerTest; CPPUNIT_TEST_SUITE_REGISTRATION( XercesDomDocumentHandlerTest ); class XercesDomDocumentHandlerTest : public CppUnit::TestCase { CPPUNIT_TEST_SUITE( XercesDomDocumentHandlerTest ); CPPUNIT_TEST(testDefaultConstructor_PointsNoWhere); CPPUNIT_TEST(testSetDocument_ChangesSelectionToRoot); CPPUNIT_TEST(testCreate); CPPUNIT_TEST(testCreate_whenTwice); CPPUNIT_TEST(testRead); CPPUNIT_TEST(testRead_withErrors); CPPUNIT_TEST(testWriteSelection); CPPUNIT_TEST(testWriteDocument); CPPUNIT_TEST(testSelect_withEmptyPathKeepsTheSelection); CPPUNIT_TEST(testSelect_withRelativePathMovesTheSelection); CPPUNIT_TEST(testSelect_withRelativePathIgnoringNonElements); CPPUNIT_TEST(testSelect_withRelativePathIgnoringElementsWithDifferentNames); CPPUNIT_TEST(testSelect_givesExceptionWheneverTheNameIsNotFound); CPPUNIT_TEST(testSelect_multipleLevelSelection); CPPUNIT_TEST(testSelect_badPathKeepsTheSelection); CPPUNIT_TEST(testSelect_withSomeMoreLevels); CPPUNIT_TEST(testSelect_successiveRelative); CPPUNIT_TEST(testSelect_withAbsolutePath); CPPUNIT_TEST(testSelect_absoluteWithBadRootNameFails); CPPUNIT_TEST(testSelect_absoluteFailsKeepsOldSelection); CPPUNIT_TEST(testSelect_withASingleBarGoesToRoot); CPPUNIT_TEST(testWriteSelection_withAMovedSelection); CPPUNIT_TEST(testWriteDocument_withAMovedSelectionBehavesTheSame); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { XercesInitializer::require(); mTargetStream.str(""); } /// Common clean up, executed after each test method void tearDown() { } private: std::stringstream mTargetStream; void testDefaultConstructor_PointsNoWhere() { XercesDomDocumentHandler doc; CPPUNIT_ASSERT_EQUAL((xercesc::DOMElement*)0,doc.getSelection()); } void testSetDocument_ChangesSelectionToRoot() { xercesc::DOMImplementation * imp = xercesc::DOMImplementation::getImplementation(); xercesc::DOMDocument * domDoc = imp->createDocument(0,U("RootNode"),0); XercesDomDocumentHandler doc; doc.setDocument(domDoc); CPPUNIT_ASSERT_EQUAL(domDoc->getDocumentElement(),doc.getSelection()); } void testCreate() { XercesDomDocumentHandler doc; doc.create("RootNode"); std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("RootNode"),result); } void testCreate_whenTwice() { XercesDomDocumentHandler doc; doc.create("RootNode"); doc.create("RootNode2"); std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("RootNode2"),result); } void testRead() { XercesDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("LoadedRoot"),result); } void testRead_withErrors() { XercesDomDocumentHandler doc; std::istringstream stream(""); try { doc.read(stream); CPPUNIT_FAIL("Should throw an exception"); } catch(CLAM::XmlStorageErr & err) { std::string expected = "\nXML Parser Errors:\n" "Fatal Error at file CLAMParser, line 1, col 31:\n" "Expected end of tag 'UnclossedChild'\n"; CPPUNIT_ASSERT_EQUAL(expected,std::string(err.what())); } CPPUNIT_ASSERT_EQUAL((xercesc::DOMElement*)0,doc.getSelection()); } void testWriteSelection() { XercesDomDocumentHandler doc; std::istringstream is(""); doc.read(is); std::ostringstream os; doc.writeSelection(os); CPPUNIT_ASSERT_EQUAL(is.str(),os.str()); } void testWriteDocument() { XercesDomDocumentHandler doc; std::istringstream is(""); doc.read(is); std::ostringstream os; doc.writeDocument(os); CPPUNIT_ASSERT_EQUAL(""+is.str(),os.str()); } void testSelect_withEmptyPathKeepsTheSelection() { XercesDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath(""); std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("LoadedRoot"),result); } void testSelect_withRelativePathMovesTheSelection() { XercesDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Child"); std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("Child"),result); } void testSelect_withRelativePathIgnoringNonElements() { XercesDomDocumentHandler doc; std::istringstream stream("ToBe Ignored "); doc.read(stream); doc.selectPath("Child"); std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("Child"),result); } void testSelect_withRelativePathIgnoringElementsWithDifferentNames() { XercesDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Child"); std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("Child"),result); } void testSelect_givesExceptionWheneverTheNameIsNotFound() { XercesDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); try { doc.selectPath("LostChild"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::XmlStorageErr & err) { std::string expected = "Wrong path step 'LostChild'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("LoadedRoot"),result); } void testSelect_multipleLevelSelection() { XercesDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Element/Child"); std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("Child"),result); } void testSelect_badPathKeepsTheSelection() { XercesDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); try { doc.selectPath("Element/BadChild"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::XmlStorageErr & err) { std::string expected = "Wrong path step 'BadChild'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("LoadedRoot"),result); } void testSelect_withSomeMoreLevels() { XercesDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Element/Child/SubChild"); std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("SubChild"),result); } void testSelect_successiveRelative() { XercesDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Element/Child"); doc.selectPath("SubChild"); std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("SubChild"),result); } void testSelect_withAbsolutePath() { XercesDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("/LoadedRoot/Element/Child"); std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("Child"),result); } void testSelect_absoluteWithBadRootNameFails() { XercesDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Element"); try { doc.selectPath("/BadRoot/Element/Child"); CPPUNIT_FAIL("Should throw an exception"); } catch (CLAM::XmlStorageErr & err) { std::string expected = "Wrong root name, expected 'BadRoot' but found 'LoadedRoot'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("Element"),result); } void testSelect_absoluteFailsKeepsOldSelection() { XercesDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Element/OtherChild"); try { doc.selectPath("/LoadedRoot/Element/LostChild"); CPPUNIT_FAIL("Should throw an exception"); } catch (CLAM::XmlStorageErr & err) { std::string expected = "Wrong path step 'LostChild'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("OtherChild"),result); } void testSelect_withASingleBarGoesToRoot() { XercesDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Element/OtherChild"); doc.selectPath("/"); std::string result(L(doc.getSelection()->getNodeName())); CPPUNIT_ASSERT_EQUAL(std::string("LoadedRoot"),result); } void testWriteSelection_withAMovedSelection() { XercesDomDocumentHandler doc; std::istringstream is(""); doc.read(is); doc.selectPath("Element"); std::ostringstream os; doc.writeSelection(os); std::string expected = ""; CPPUNIT_ASSERT_EQUAL(expected,os.str()); } void testWriteDocument_withAMovedSelectionBehavesTheSame() { XercesDomDocumentHandler doc; std::istringstream is(""); doc.read(is); std::ostringstream os; doc.writeDocument(os); CPPUNIT_ASSERT_EQUAL(""+is.str(),os.str()); } }; } // namespace Test } // namespace Cuidado #endif // USE_XERCES clam-1.4.0/test/UnitTests/XmlTests/LibXmlDomDocumentHandlerTest.cxx0000644000000000000000000002423411160517505024050 0ustar rootroot#ifdef USE_XMLPP #include #include "cppUnitHelper.hxx" #include "LibXmlDomDocumentHandler.hxx" // CLAM #include #include // TODO: Get the read errors namespace CLAM { namespace Test { class LibXmlDomDocumentHandlerTest; CPPUNIT_TEST_SUITE_REGISTRATION( LibXmlDomDocumentHandlerTest ); class LibXmlDomDocumentHandlerTest : public CppUnit::TestCase { CPPUNIT_TEST_SUITE( LibXmlDomDocumentHandlerTest ); CPPUNIT_TEST(testDefaultConstructor_PointsNoWhere); CPPUNIT_TEST(testSetDocument_ChangesSelectionToRoot); CPPUNIT_TEST(testCreate); CPPUNIT_TEST(testCreate_whenTwice); CPPUNIT_TEST(testRead); CPPUNIT_TEST(testRead_withErrors); // CPPUNIT_TEST(testWriteSelection); CPPUNIT_TEST(testWriteDocument); CPPUNIT_TEST(testSelect_withEmptyPathKeepsTheSelection); CPPUNIT_TEST(testSelect_withRelativePathMovesTheSelection); CPPUNIT_TEST(testSelect_withRelativePathIgnoringNonElements); CPPUNIT_TEST(testSelect_withRelativePathIgnoringElementsWithDifferentNames); CPPUNIT_TEST(testSelect_givesExceptionWheneverTheNameIsNotFound); CPPUNIT_TEST(testSelect_multipleLevelSelection); CPPUNIT_TEST(testSelect_badPathKeepsTheSelection); CPPUNIT_TEST(testSelect_withSomeMoreLevels); CPPUNIT_TEST(testSelect_successiveRelative); CPPUNIT_TEST(testSelect_withAbsolutePath); CPPUNIT_TEST(testSelect_absoluteWithBadRootNameFails); CPPUNIT_TEST(testSelect_absoluteFailsKeepsOldSelection); CPPUNIT_TEST(testSelect_withASingleBarGoesToRoot); /* CPPUNIT_TEST(testWriteSelection_withAMovedSelection); */ CPPUNIT_TEST(testWriteDocument_withAMovedSelectionBehavesTheSame); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { mTargetStream.str(""); } /// Common clean up, executed after each test method void tearDown() { } private: std::stringstream mTargetStream; void testDefaultConstructor_PointsNoWhere() { LibXmlDomDocumentHandler doc; CPPUNIT_ASSERT_EQUAL((xmlpp::Element*)0,doc.getSelection()); } void testSetDocument_ChangesSelectionToRoot() { xmlpp::Document * domDoc = new xmlpp::Document; xmlpp::Element * root = domDoc->create_root_node("RootNode"); LibXmlDomDocumentHandler doc; doc.setDocument(domDoc); CPPUNIT_ASSERT_EQUAL(root,doc.getSelection()); } void testCreate() { LibXmlDomDocumentHandler doc; doc.create("RootNode"); std::string result=doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("RootNode"),result); } void testCreate_whenTwice() { LibXmlDomDocumentHandler doc; doc.create("RootNode"); doc.create("RootNode2"); std::string result=doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("RootNode2"),result); } void testRead() { LibXmlDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); std::string result = doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("LoadedRoot"),result); } void testRead_withErrors() { LibXmlDomDocumentHandler doc; std::istringstream stream(""); try { doc.read(stream); CPPUNIT_FAIL("Should throw an exception"); } catch(CLAM::XmlStorageErr & err) { std::string expected = "\nXML Parser Errors:\n" "Document not well-formed.\n"; CPPUNIT_ASSERT_EQUAL(expected,std::string(err.what())); } CPPUNIT_ASSERT_EQUAL((xmlpp::Element*)0,doc.getSelection()); } /* void testWriteSelection() { LibXmlDomDocumentHandler doc; std::istringstream is(""); doc.read(is); std::ostringstream os; doc.writeSelection(os); CPPUNIT_ASSERT_EQUAL(is.str(),os.str()); } */ void testWriteDocument() { LibXmlDomDocumentHandler doc; std::istringstream is(""); doc.read(is); std::ostringstream os; doc.writeDocument(os); CPPUNIT_ASSERT_EQUAL("\n"+is.str()+"\n",os.str()); } void testSelect_withEmptyPathKeepsTheSelection() { LibXmlDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath(""); std::string result = doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("LoadedRoot"),result); } void testSelect_withRelativePathMovesTheSelection() { LibXmlDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Child"); std::string result = doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("Child"),result); } void testSelect_withRelativePathIgnoringNonElements() { LibXmlDomDocumentHandler doc; std::istringstream stream("ToBe Ignored "); doc.read(stream); doc.selectPath("Child"); std::string result = doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("Child"),result); } void testSelect_withRelativePathIgnoringElementsWithDifferentNames() { LibXmlDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Child"); std::string result = doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("Child"),result); } void testSelect_givesExceptionWheneverTheNameIsNotFound() { LibXmlDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); try { doc.selectPath("LostChild"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::XmlStorageErr & err) { std::string expected = "Wrong path step 'LostChild'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } std::string result = doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("LoadedRoot"),result); } void testSelect_multipleLevelSelection() { LibXmlDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Element/Child"); std::string result = doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("Child"),result); } void testSelect_badPathKeepsTheSelection() { LibXmlDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); try { doc.selectPath("Element/BadChild"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::XmlStorageErr & err) { std::string expected = "Wrong path step 'BadChild'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } std::string result = doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("LoadedRoot"),result); } void testSelect_withSomeMoreLevels() { LibXmlDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Element/Child/SubChild"); std::string result = doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("SubChild"),result); } void testSelect_successiveRelative() { LibXmlDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Element/Child"); doc.selectPath("SubChild"); std::string result = doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("SubChild"),result); } void testSelect_withAbsolutePath() { LibXmlDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("/LoadedRoot/Element/Child"); std::string result = doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("Child"),result); } void testSelect_absoluteWithBadRootNameFails() { LibXmlDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Element"); try { doc.selectPath("/BadRoot/Element/Child"); CPPUNIT_FAIL("Should throw an exception"); } catch (CLAM::XmlStorageErr & err) { std::string expected = "Wrong root name, expected 'BadRoot' but found 'LoadedRoot'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } std::string result = doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("Element"),result); } void testSelect_absoluteFailsKeepsOldSelection() { LibXmlDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Element/OtherChild"); try { doc.selectPath("/LoadedRoot/Element/LostChild"); CPPUNIT_FAIL("Should throw an exception"); } catch (CLAM::XmlStorageErr & err) { std::string expected = "Wrong path step 'LostChild'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } std::string result = doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("OtherChild"),result); } void testSelect_withASingleBarGoesToRoot() { LibXmlDomDocumentHandler doc; std::istringstream stream(""); doc.read(stream); doc.selectPath("Element/OtherChild"); doc.selectPath("/"); std::string result = doc.getSelection()->get_name(); CPPUNIT_ASSERT_EQUAL(std::string("LoadedRoot"),result); } /* void testWriteSelection_withAMovedSelection() { LibXmlDomDocumentHandler doc; std::istringstream is(""); doc.read(is); doc.selectPath("Element"); std::ostringstream os; doc.writeSelection(os); std::string expected = ""; CPPUNIT_ASSERT_EQUAL(expected,os.str()); } */ void testWriteDocument_withAMovedSelectionBehavesTheSame() { LibXmlDomDocumentHandler doc; std::istringstream is(""); doc.read(is); std::ostringstream os; doc.writeDocument(os); CPPUNIT_ASSERT_EQUAL("\n"+is.str()+"\n",os.str()); } }; } // namespace Test } // namespace Cuidado #endif//USE_XMLPP clam-1.4.0/test/UnitTests/XmlTests/LibXmlDomWriterTest.cxx0000644000000000000000000001544611160472331022252 0ustar rootroot#ifdef USE_XMLPP #include #include "cppUnitHelper.hxx" #include "LibXmlDomWriter.hxx" // CLAM #include namespace CLAM { namespace Test { class LibXmlDomWriterTest; CPPUNIT_TEST_SUITE_REGISTRATION( LibXmlDomWriterTest ); class LibXmlDomWriterTest : public CppUnit::TestCase { CPPUNIT_TEST_SUITE( LibXmlDomWriterTest ); CPPUNIT_TEST(testEmptyDocument); CPPUNIT_TEST(testPlainContent); CPPUNIT_TEST(testEmptyElement); CPPUNIT_TEST(testElementWithPlainContent); CPPUNIT_TEST(testElementWithInnerElement); CPPUNIT_TEST(testEmptyElementWithAttribute); CPPUNIT_TEST(testEmptyElementWithAttributes); CPPUNIT_TEST(testEmptyElementWithReversedOrderAttributes); CPPUNIT_TEST(testEmptyElementWithSameAttributeNameTwice); CPPUNIT_TEST(testNonEmptyElementWithAttribute); CPPUNIT_TEST(testDocumentWithFullContent); CPPUNIT_TEST(testDocumentWithFullContentAndIndentation); CPPUNIT_TEST(testDocumentWithFullContentAndIndentation_elementWithContentAreInlined); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { mTargetStream.str(""); mDocument = new xmlpp::Document; mRoot = mDocument->create_root_node( "TestDoc" // root element name // ,"http://iua.upf.es/mtg/clam/0.8.0/2005-06" // root element namespace URI. // ,"clam" // namespace prefix ); mHeader = "\n"; } /// Common clean up, executed after each test method void tearDown() { delete mDocument; } private: std::stringstream mTargetStream; xmlpp::Document * mDocument; xmlpp::Element * mRoot; std::string mHeader; void assertXmlBodyEqual(const std::string & body) { CPPUNIT_ASSERT_EQUAL(mHeader + body +"\n", mTargetStream.str()); } void testEmptyDocument() { LibXmlDomWriter writer; writer.write(mTargetStream, mDocument); assertXmlBodyEqual(""); } void testPlainContent() { mRoot->add_child_text("Content"); LibXmlDomWriter writer; writer.write(mTargetStream, mDocument); assertXmlBodyEqual("Content"); } void testEmptyElement() { mRoot->add_child("EmptyElement"); LibXmlDomWriter writer; writer.write(mTargetStream, mDocument); assertXmlBodyEqual(""); } void testElementWithPlainContent() { xmlpp::Element * domElement = mRoot->add_child("Element"); domElement->add_child_text("Content"); LibXmlDomWriter writer; writer.write(mTargetStream, mDocument); assertXmlBodyEqual("Content"); } void testElementWithInnerElement() { mRoot ->add_child("Element") ->add_child("InnerElement") ->add_child_text("Content"); LibXmlDomWriter writer; writer.write(mTargetStream, mDocument); assertXmlBodyEqual("Content"); } void testEmptyElementWithAttribute() { xmlpp::Element * domElement = mRoot->add_child("Element"); domElement->set_attribute("attribute","Attribute value"); LibXmlDomWriter writer; writer.write(mTargetStream, mDocument); assertXmlBodyEqual(""); } void testEmptyElementWithAttributes() { xmlpp::Element * domElement = mRoot->add_child("Element"); domElement->set_attribute("attribute1","Attribute 1 value"); domElement->set_attribute("attribute2","Attribute 2 value"); LibXmlDomWriter writer; writer.write(mTargetStream, mDocument); assertXmlBodyEqual(""); } void testEmptyElementWithReversedOrderAttributes() { xmlpp::Element * domElement = mRoot->add_child("Element"); domElement->set_attribute("attribute2","Attribute 2 value"); domElement->set_attribute("attribute1","Attribute 1 value"); LibXmlDomWriter writer; writer.write(mTargetStream, mDocument); // Unlike Xerces-C it outputs attributes in insertion order assertXmlBodyEqual(""); } void testEmptyElementWithSameAttributeNameTwice() { xmlpp::Element * domElement = mRoot->add_child("Element"); domElement->set_attribute("attribute","Attribute value 1"); domElement->set_attribute("attribute","Attribute value 2"); LibXmlDomWriter writer; writer.write(mTargetStream, mDocument); // It gets the last one assertXmlBodyEqual(""); } void testNonEmptyElementWithAttribute() { xmlpp::Element * domElement = mRoot->add_child("Element"); domElement->add_child("InnerElement"); domElement->set_attribute("attribute","Attribute value"); LibXmlDomWriter writer; writer.write(mTargetStream, mDocument); assertXmlBodyEqual(""); } void testDocumentWithFullContent() { xmlpp::Element * domElement = mRoot->add_child("Element"); domElement->add_child_text("Content"); domElement->add_child("InnerElement"); domElement->set_attribute("attribute","Attribute value"); LibXmlDomWriter writer; writer.write(mTargetStream, mDocument); assertXmlBodyEqual( "" "" "Content" "" "" "" ); } void testDocumentWithFullContentAndIndentation() { xmlpp::Element * domElement = mRoot->add_child("Element"); domElement->add_child("InnerElement")->add_child_text("Content"); domElement->set_attribute("attribute","Attribute value"); LibXmlDomWriter writer; writer.DoIndentedFormat(true); writer.write(mTargetStream, mDocument); // LibXml does a very weird indentation!! CPPUNIT_ASSERT_EQUAL(std::string( "\n" "\n" " \n" " Content\n" " \n" "\n" ), mTargetStream.str()); } void testDocumentWithFullContentAndIndentation_elementWithContentAreInlined() { xmlpp::Element * domElement = mRoot->add_child("Element"); xmlpp::Element * subElement = domElement->add_child("InnerElement"); subElement->add_child_text("Content"); subElement->add_child("InnestElement"); domElement->set_attribute("attribute","Attribute value"); LibXmlDomWriter writer; writer.DoIndentedFormat(true); writer.write(mTargetStream, mDocument); // LibXml does a very weird indentation!! CPPUNIT_ASSERT_EQUAL(std::string( "\n" "\n" " \n" " Content\n" " \n" "\n" ), mTargetStream.str()); } }; } // namespace Test } // namespace CLAM #endif//USE_XMLPP clam-1.4.0/test/UnitTests/XmlTests/XmlMockUpObjects.hxx0000644000000000000000000000473210442000724021553 0ustar rootroot#ifndef _XML_MOCK_UP_OBJECTS_HXX_ #define _XML_MOCK_UP_OBJECTS_HXX_ #include "BasicXMLable.hxx" // CLAM #include "Component.hxx" // CLAM #include namespace CLAM { namespace Test { class XmlMockUpBasic : public BasicXMLable { public: XmlMockUpBasic(const char * name=0, bool isElement=false) : BasicXMLable(name, isElement) { _loadOk=true; } void setContent(const std::string & content) { _content = content; } std::string XMLContent() const { return _content; } //* Extracts the content from the stream. bool XMLContent(std::istream & str) { _content=""; str >> _content; return str!=NULL; } virtual std::string structureTrace(unsigned level) { return std::string(level,'.')+"B'"+_content+"'"+(_loadOk?"":"[unloaded]")+"\n"; } void setLoadOk(bool storageLoadReturnValue) { _loadOk = storageLoadReturnValue; } protected: std::string _content; bool _loadOk; }; class CompositeOfXmlables : public Component { public: CompositeOfXmlables() {} virtual ~CompositeOfXmlables() {} void add(XmlMockUpBasic & part) { _parts.push_back(&part); } const char * GetClassName() const { return "CLAMTest::CompositeOfXmlables";} void StoreOn(Storage & store) const { std::list::const_iterator it = _parts.begin(); for (; it!= _parts.end();it++) store.Store(**it); } void LoadFrom(Storage & store) { std::list::const_iterator it = _parts.begin(); for (; it!= _parts.end();it++) { bool result = store.Load(**it); (*it)->setLoadOk(result); } } std::string childStructureTrace(unsigned childLevel) { std::string result; std::list::iterator it = _parts.begin(); for (;it!=_parts.end();it++) { result+=(*it)->structureTrace(childLevel); } return result; } private: std::list _parts; }; class XmlMockUpComponent : public XmlMockUpBasic, public CompositeOfXmlables { public: XmlMockUpComponent(const char * name=0, bool isElement=false) : XmlMockUpBasic(name, isElement) {} const char * GetClassName() const { return "CLAMTest::XmlMockUpComponent";} virtual std::string structureTrace(unsigned level) { std::string indentation(level,'.'); return indentation+"C'"+_content+"'"+(_loadOk?"":"[unloaded]")+"\n"+ indentation+"{\n"+ childStructureTrace(level+1) + indentation+"}\n"; } }; } // namespace Test } // namespace Cuidado #endif//_XML_MOCK_UP_OBJECTS_HXX_ clam-1.4.0/test/UnitTests/XmlTests/XercesDomReaderTest.cxx0000644000000000000000000001225210630505361022233 0ustar rootroot#ifdef USE_XERCES #include #include "cppUnitHelper.hxx" #include "XercesDomWriter.hxx" // CLAM #include "XercesDomReader.hxx" // CLAM #include "XercesInitializer.hxx" // CLAM #include "XercesEncodings.hxx" // CLAM #include #include namespace CLAM { namespace Test { /** * TODO: * - When there are two errors the message is incongruent * - Test entity translation ie < > &... */ class XercesDomReaderTest; CPPUNIT_TEST_SUITE_REGISTRATION( XercesDomReaderTest ); class XercesDomReaderTest : public CppUnit::TestCase { CPPUNIT_TEST_SUITE( XercesDomReaderTest ); CPPUNIT_TEST(testBadSource_throwsException); CPPUNIT_TEST(testNonXml_throwsException); CPPUNIT_TEST(testEmptyDocument); CPPUNIT_TEST(testFullDocument); CPPUNIT_TEST(testFullDocument_whenDuplicatedAttribute); CPPUNIT_TEST(testFullDocument_whenUnclosedTag); CPPUNIT_TEST(testFullDocument_whenClosingUnopenedTag); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { XercesInitializer::require(); mTargetStream.str(""); } /// Common clean up, executed after each test method void tearDown() { } private: std::stringstream mTargetStream; std::string xmlHeader() { return ""; } void testBadSource_throwsException() { std::ifstream toRead("NonExistingFile.xml"); XercesDomReader reader; try { xercesc::DOMNode * document = reader.read(toRead); CPPUNIT_FAIL("Read should have thrown an exception"); document=0; // Use the un used var to stop warnings. } catch (XmlStorageErr & e) { CPPUNIT_ASSERT_EQUAL( std::string("Unable to open the document source"), std::string(e.what())); } } void testNonXml_throwsException() { std::istringstream toRead("ument />"); XercesDomReader reader; try { xercesc::DOMNode * document = reader.read(toRead); CPPUNIT_FAIL("Read should have thrown an exception"); document=0; // Use the un used var to stop warnings. } catch (XmlStorageErr & e) { CPPUNIT_ASSERT_EQUAL( std::string( "\n" "XML Parser Errors:\n" "Fatal Error at file CLAMParser, line 1, col 1:\n" "Invalid document structure\n" ), std::string(e.what())); } } void testEmptyDocument() { std::istringstream toRead(""); XercesDomReader reader; xercesc::DOMDocument * doc = reader.read(toRead); XercesDomWriter writer; writer.write(mTargetStream, doc); CPPUNIT_ASSERT_EQUAL(std::string( xmlHeader() + "" ), mTargetStream.str()); } void testFullDocument() { const char * toParse = "" "" "Content" "" "" ""; std::istringstream toRead(toParse); XercesDomReader reader; xercesc::DOMDocument * doc = reader.read(toRead); XercesDomWriter writer; writer.write(mTargetStream, doc); CPPUNIT_ASSERT_EQUAL(xmlHeader()+toParse, mTargetStream.str()); } void testFullDocument_whenDuplicatedAttribute() { const char * toParse = "" "" "Content" "" "" ""; std::istringstream toRead(toParse); XercesDomReader reader; try { xercesc::DOMNode * document = reader.read(toRead); CPPUNIT_FAIL("Read should have thrown an exception"); document=0; // Use the un used var to stop warnings. } catch (XmlStorageErr & e) { CPPUNIT_ASSERT_EQUAL(std::string( "\n" "XML Parser Errors:\n" "Fatal Error at file CLAMParser, line 1, col 71:\n" "The attribute 'attribute' is already used in element 'Element'\n" ), std::string(e.what())); } } void testFullDocument_whenUnclosedTag() { const char * toParse = "" "" "Content" "" "" "" ""; std::istringstream toRead(toParse); XercesDomReader reader; try { xercesc::DOMNode * document = reader.read(toRead); CPPUNIT_FAIL("Read should have thrown an exception"); document=0; // Use the un used var to stop warnings. } catch (XmlStorageErr & e) { CPPUNIT_ASSERT_EQUAL(std::string( "\n" "XML Parser Errors:\n" "Fatal Error at file CLAMParser, line 1, col 81:\n" "Expected end of tag 'Unclosed'\n" ), std::string(e.what())); } } void testFullDocument_whenClosingUnopenedTag() { const char * toParse = "" "" "Content" "" "" "" ""; std::istringstream toRead(toParse); XercesDomReader reader; try { xercesc::DOMNode * document = reader.read(toRead); CPPUNIT_FAIL("Read should have thrown an exception"); document=0; // Use the un used var to stop warnings. } catch (XmlStorageErr & e) { CPPUNIT_ASSERT_EQUAL(std::string( "\n" "XML Parser Errors:\n" "Fatal Error at file CLAMParser, line 1, col 71:\n" "Expected end of tag 'Element'\n" ), std::string(e.what())); } } }; } // namespace Test } // namespace Cuidado #endif //USE_XERCES clam-1.4.0/test/UnitTests/XmlTests/LibXmlDomReaderTest.cxx0000644000000000000000000001135711160472331022175 0ustar rootroot#ifdef USE_XMLPP #include #include "cppUnitHelper.hxx" #include "LibXmlDomReader.hxx" // CLAM #include "LibXmlDomWriter.hxx" // CLAM #include #include namespace CLAM { namespace Test { /** * TODO: * - When there are two errors the message is incongruent * - Test entity translation ie < > &... */ class LibXmlDomReaderTest; CPPUNIT_TEST_SUITE_REGISTRATION( LibXmlDomReaderTest ); class LibXmlDomReaderTest : public CppUnit::TestCase { CPPUNIT_TEST_SUITE( LibXmlDomReaderTest ); CPPUNIT_TEST(testBadSource_throwsException); CPPUNIT_TEST(testNonXml_throwsException); CPPUNIT_TEST(testEmptyDocument); CPPUNIT_TEST(testFullDocument); CPPUNIT_TEST(testFullDocument_whenDuplicatedAttribute); CPPUNIT_TEST(testFullDocument_whenUnclosedTag); CPPUNIT_TEST(testFullDocument_whenClosingUnopenedTag); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { mTargetStream.str(""); } /// Common clean up, executed after each test method void tearDown() { } private: std::stringstream mTargetStream; void assertBodyEquals(const std::string & expectedBody) { std::string header = "\n"; CPPUNIT_ASSERT_EQUAL(header + expectedBody + "\n", mTargetStream.str()); } void testBadSource_throwsException() { std::ifstream toRead("NonExistingFile.xml"); LibXmlDomReader reader; try { xmlpp::Document * document = reader.read(toRead); CPPUNIT_FAIL("Read should have thrown an exception"); document=0; } catch (XmlStorageErr & e) { CPPUNIT_ASSERT_EQUAL( std::string("Unable to open the document source"), std::string(e.what())); } } void testNonXml_throwsException() { std::istringstream toRead("ument />"); LibXmlDomReader reader; try { xmlpp::Document * document = reader.read(toRead); CPPUNIT_FAIL("Read should have thrown an exception"); document=0; // Use the un used var to stop warnings. } catch (XmlStorageErr & e) { CPPUNIT_ASSERT_EQUAL( std::string( "\n" "XML Parser Errors:\n" "Document not well-formed.\n" ), std::string(e.what())); } } void testEmptyDocument() { std::istringstream toRead(""); LibXmlDomReader reader; xmlpp::Document * doc = reader.read(toRead); LibXmlDomWriter writer; writer.write(mTargetStream, doc); assertBodyEquals(""); } void testFullDocument() { const char * toParse = "" "" "Content" "" "" ""; std::istringstream toRead(toParse); LibXmlDomReader reader; xmlpp::Document * doc = reader.read(toRead); LibXmlDomWriter writer; writer.write(mTargetStream, doc); assertBodyEquals(toParse); } void testFullDocument_whenDuplicatedAttribute() { const char * toParse = "" "" "Content" "" "" ""; std::istringstream toRead(toParse); LibXmlDomReader reader; try { xmlpp::Document * document = reader.read(toRead); CPPUNIT_FAIL("Read should have thrown an exception"); document=0; // Use the un used var to stop warnings. } catch (XmlStorageErr & e) { CPPUNIT_ASSERT_EQUAL(std::string( "\n" "XML Parser Errors:\n" "Document not well-formed.\n" ), std::string(e.what())); } } void testFullDocument_whenUnclosedTag() { const char * toParse = "" "" "Content" "" "" "" ""; std::istringstream toRead(toParse); LibXmlDomReader reader; try { xmlpp::Document * document = reader.read(toRead); CPPUNIT_FAIL("Read should have thrown an exception"); document=0; // Use the un used var to stop warnings. } catch (XmlStorageErr & e) { CPPUNIT_ASSERT_EQUAL(std::string( "\n" "XML Parser Errors:\n" "Document not well-formed.\n" ), std::string(e.what())); } } void testFullDocument_whenClosingUnopenedTag() { const char * toParse = "" "" "Content" "" "" "" ""; std::istringstream toRead(toParse); LibXmlDomReader reader; try { xmlpp::Document * document = reader.read(toRead); CPPUNIT_FAIL("Read should have thrown an exception"); document=0; // Use the un used var to stop warnings. } catch (XmlStorageErr & e) { CPPUNIT_ASSERT_EQUAL(std::string( "\n" "XML Parser Errors:\n" "Document not well-formed.\n" ), std::string(e.what())); } } }; } // namespace Test } // namespace Cuidado #endif//USE_XMLPP clam-1.4.0/test/UnitTests/SConscript0000644000000000000000000000573611163714540016076 0ustar rootroot#!/usr/bin/python Import('env') import sys, os, glob def scanFiles(pattern, paths) : files = [] for path in paths : files+=glob.glob(os.path.join(path,pattern)) return files def recursiveDirs(root) : return filter( (lambda a : a.rfind( ".svn")==-1 ), [ a[0] for a in os.walk(root)] ) def unique(list) : return dict.fromkeys(list).keys() folders = [ os.path.join('.'), os.path.join('CommonHelpers'), os.path.join('ControlsTests'), os.path.join('DescriptorsTests'), os.path.join('DynamicTypeTests'), os.path.join('FactoryTest'), os.path.join('FlowControlTests'), os.path.join('NonComponentData'), os.path.join('PortsTest'), os.path.join('ProcessingBaseTests'), os.path.join('ProcessingDataTests'), os.path.join('ProcessingsTests'), os.path.join('StandardTests'), os.path.join('TonalAnalysis'), os.path.join('ToolsTests'), os.path.join('XmlTests'), os.path.join('VisualizationTests'), ] blacklist = [ os.path.join('.','TestRunnerQt.cxx'), os.path.join('FactoryTest','PolymorphicTest.cxx'), os.path.join('ProcessingsTests','AudioMixerTest.cxx'), # Uses old fashioned idioms that don't compil os.path.join('TonalAnalysis','ChordCorrelatorTest.cxx'), # recognized labels not the current ones os.path.join('TonalAnalysis','ChordExtractorTest.cxx'), # last too long os.path.join('DescriptorsTests','ProofOfConceptTest.cxx'), # Fails always because FFT size, should be rewritten and moved to functional tests ] if 'crossmingw' in env['TOOLS'] : # They lauch exceptions unsuported in crossmingw until upgrade blacklist += [ os.path.join('DescriptorsTests','DescriptionXmlTest.cxx'), os.path.join('DescriptorsTests','SpectralDescriptorsTest.cxx'), os.path.join('DescriptorsTests','SpectralPeakDescriptorsTest.cxx'), os.path.join('ProcessingBaseTests','ProcessingTest.cxx'), # this one just don't notice the exception os.path.join('NonComponentData','FlagsTest.cxx'), os.path.join('FlowControlTests','NetworkTest.cxx'), os.path.join('DynamicTypeTests','DynamicTypeBasicTest.cxx'), os.path.join('XmlTests','LibXmlDomDocumentHandlerTest.cxx'), os.path.join('XmlTests','LibXmlDomReaderTest.cxx'), os.path.join('XmlTests','XercesDom2ClamObjectsTest.cxx'), ] #folders = [ os.path.join('..','..','..','test', folder) for folder in folders ] #blacklist = [ os.path.join('..','..','..','test', blacksheep) for blacksheep in blacklist ] sources = scanFiles('*.cxx', folders) headers = scanFiles('*.hxx', folders) for blacksheep in blacklist : sources.remove(blacksheep) unit_tests = env.Program( 'UnitTests', sources ) test_alias = Alias( 'run_unit_tests', [unit_tests], unit_tests[0].abspath ) AlwaysBuild( test_alias ) # Workaround to have only some unit-tests in a separate executable #simple_test = [ 'TestRunnerConsole.cxx', #'TypedControlsTests/TypedControlsTests.cxx' ] #simple_unit_tests = env.Program( 'simpleUnitTest', simple_test ) #simple_unit_tests_alias = Alias( 'simple_unit_tests', [simple_unit_tests], simple_unit_tests[0].abspath ) #AlwaysBuild( simple_unit_tests ) clam-1.4.0/test/UnitTests/CommonHelpers/0000755000000000000000000000000011344231440016616 5ustar rootrootclam-1.4.0/test/UnitTests/CommonHelpers/XMLTestHelper.hxx0000644000000000000000000000450311124176171022016 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _XMLTESTHELPER_ #define _XMLTESTHELPER_ #include #include #include #include "XMLStorage.hxx" // CLAM using namespace CLAM; namespace CLAMTest { /** * Returns true if the XML output from 'tested' and the XML output * generated from an object restored from this output matches. */ template bool XMLInputOutputMatches(T & outObject, const char * filename) { std::stringstream out; std::ostringstream in; T inObject; #ifdef CLAM_USE_XML { // Store the arg a file and on a string XMLStorage::Dump(outObject, "Object", out); } { // Recover the objec on superIn XMLStorage::Restore(inObject, out); } { // Store it on a string again XMLStorage::Dump(inObject, "Object", in); } #endif//CLAM_USE_XML CPPUNIT_ASSERT_EQUAL(out.str(),in.str()); return in.str()==out.str(); } void checkXmlEqual( const std::string & expectedXml, const std::string & actualXml, CppUnit::SourceLine sourceLine ); /// Asserts that two XML strings are equivalent. #define CLAMTEST_ASSERT_XML_EQUAL( expected, actual ) \ ::CLAMTest::checkXmlEqual( expected, actual, \ CPPUNIT_SOURCELINE() ) inline std::string xmlHeader() { return #ifdef USE_XERCES ""; #else "\n"; #endif } inline std::string xmlFooter() { return #ifdef USE_XERCES ""; #else "\n"; #endif } } #endif//_XMLTESTHELPER_ clam-1.4.0/test/UnitTests/CommonHelpers/DummyProcessingData.hxx0000644000000000000000000000070210610720021023261 0ustar rootroot#ifndef _DummyProcessingData_hxx_ #define _DummyProcessingData_hxx_ #include "ProcessingData.hxx" // CLAM namespace CLAMTest { class DummyProcessingData : public CLAM::ProcessingData { int mState; public: DYNAMIC_TYPE_USING_INTERFACE( DummyProcessingData, 0, CLAM::ProcessingData ); public: void DefaultInit() { mState = -1; } void SetState(int val) { mState = val; } int GetState() { return mState; } }; } // namespace CLAMTest #endif clam-1.4.0/test/UnitTests/CommonHelpers/XMLTestHelper.cxx0000644000000000000000000001070111016526216022005 0ustar rootroot #include "XMLTestHelper.hxx" #include #include #include namespace CLAMTest { /*! Uniformise an XML string. * Strips spaces between attribut in Element. * \warning Attribute values must be double-quoted (att="value"). * No support for embedded DTD declaration */ class XmlUniformiser { public: XmlUniformiser( const std::string &xml ); std::string stripped(); private: void skipSpaces(); bool isValidIndex(); void skipNext( int count =1 ); void copyNext( int count =1 ); void skipProcessed(); void skipComment(); void copyElement(); void copyElementContent(); bool isSpace( char c ); bool isSpace(); bool startsWith( const std::string & expected ); void copyElementName(); void copyElementAttributes(); void copyAttributeName(); bool isEndOfAttributeName(); void copyAttributeValue(); void copyUntilDoubleQuote(); private: unsigned m_index; std::string m_xml; std::string m_stripped; }; int notEqualIndex( std::string expectedXml, std::string actualXml ) { unsigned index = 0; while ( index < actualXml.length() && index < expectedXml.length() && actualXml[index] == expectedXml[index] ) ++index; return index; } /// Asserts that two XML string are equivalent. void checkXmlEqual( const std::string & expectedXml, const std::string & actualXml, CppUnit::SourceLine sourceLine ) { std::string expected = XmlUniformiser( expectedXml ).stripped(); std::string actual = XmlUniformiser( actualXml ).stripped(); if ( expected == actual ) return; int index = notEqualIndex( expected, actual ); CppUnit::OStringStream message; message << "differ at index: " << index << "\n" << "expected: " << expected.substr(0,index) << "\033[1;32m" << expected.substr(index) << "\033[0m\n" << "but was: " << actual.substr(0,index) << "\033[1;31m" << actual.substr(index) << "\033[0m\n"; ::CppUnit::Asserter::fail( message.str(), sourceLine ); } XmlUniformiser::XmlUniformiser( const std::string &xml ) : m_index( 0 ), m_xml( xml ) { } std::string XmlUniformiser::stripped() { while ( isValidIndex() ) { skipSpaces(); if ( startsWith( " 0 ) ++m_index; } void XmlUniformiser::copyNext( int count ) { while ( count-- > 0 && isValidIndex() ) m_stripped += m_xml[ m_index++ ]; } bool XmlUniformiser::startsWith( const std::string & expected ) { std::string actual = m_xml.substr( m_index, expected.length() ); return actual == expected; } void XmlUniformiser::skipProcessed() { while ( isValidIndex() && !startsWith( "?>" ) ) skipNext(); if ( isValidIndex() ) skipNext( 2 ); } void XmlUniformiser::skipComment() { while ( isValidIndex() && !startsWith( "-->" ) ) skipNext(); if ( isValidIndex() ) skipNext( 3 ); } void XmlUniformiser::copyElement() { copyElementName(); copyElementAttributes(); } void XmlUniformiser::copyElementName() { while ( isValidIndex() && !( isSpace() || startsWith( ">" ) ) ) copyNext(); } void XmlUniformiser::copyElementAttributes() { do { skipSpaces(); if ( startsWith( ">" ) ) break; m_stripped += ' '; copyAttributeName(); skipSpaces(); if ( startsWith( "=" ) ) { copyNext(); copyAttributeValue(); } else // attribute should always be valued, ne ? m_stripped += ' '; } while ( isValidIndex() ); copyNext(); } void XmlUniformiser::copyAttributeName() { while ( isValidIndex() && !isEndOfAttributeName() ) copyNext(); } bool XmlUniformiser::isEndOfAttributeName() { return isSpace() || startsWith( ">" ) || startsWith( "=" ); } void XmlUniformiser::copyAttributeValue() { skipSpaces(); copyUntilDoubleQuote(); copyUntilDoubleQuote(); } void XmlUniformiser::copyUntilDoubleQuote() { while ( isValidIndex() && !startsWith("\"") ) copyNext(); copyNext(); // '"' } void XmlUniformiser::copyElementContent() { while ( isValidIndex() && !startsWith( "<" ) ) copyNext(); } } // namespace CppUnitTest clam-1.4.0/test/UnitTests/CommonHelpers/BaseLoggable.hxx0000644000000000000000000000104210610720021021644 0ustar rootroot#ifndef _BaseLoggable_hxx_ #define _BaseLoggable_hxx_ #include // class BaseLoggable needs stringstream namespace CLAMTest { /** * From this class should derive all the TestFixutures that wants to * use the Log String testing pattern. * Of course the fixture tearDown() must call ClearLog() */ class BaseLoggable { std::stringstream mLog; public: std::string GetLog() const { return mLog.str(); } void ClearLog() { mLog.str( std::string() ); } std::stringstream& ToLog() { return mLog; } }; } // namespace CLAMTest #endif clam-1.4.0/test/UnitTests/DynamicTypeTests/0000755000000000000000000000000011344231440017314 5ustar rootrootclam-1.4.0/test/UnitTests/DynamicTypeTests/DummyDynamicTypes.cxx0000644000000000000000000000257610610720021023470 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "DummyDynamicTypes.hxx" static const bool quiet=false; static const bool verbose=false; bool CLAMTest::CompWithBasics8::sTraceStatus= verbose || (!quiet && false); bool CLAMTest::CompWithBasics9::sTraceStatus= verbose || (!quiet && false); bool CLAMTest::Dyn::sTraceStatus= verbose || (!quiet && false); bool CLAMTest::DynAlt::sTraceStatus= verbose || (!quiet && false); /* // We will play with classes // A: A Component with storable members (int float and double) with value 8 // B: A clone of A but with values 9 // Dyn: A dynamicType contaning A and B as DynAttributes */ clam-1.4.0/test/UnitTests/DynamicTypeTests/DynamicTypeAdvancedTest.cxx0000644000000000000000000001371110630505361024562 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "DynamicTypeAdvancedTest.hxx" #include "XMLTestHelper.hxx" #include namespace CLAMTest { CPPUNIT_TEST_SUITE_REGISTRATION( DynamicTypeAdvancedTest ); void DynamicTypeAdvancedTest::SimpleXMLSupport() { Dyn p; p.Populate(); p.Modify( 4 ); bool match = XMLInputOutputMatches( p,__FILE__"Dyn.xml" ); CPPUNIT_ASSERT( match ); } void DynamicTypeAdvancedTest::XMLCustomizationByRedefinition() { DynAlt o; o.AddAll(); o.UpdateData(); Dyn & p = o.GetSubDyn(); p.AddAll(); p.UpdateData(); bool match = XMLInputOutputMatches( o,__FILE__"DynAlt.xml" ); CPPUNIT_ASSERT_MESSAGE("this test should be reworked (pau)", match ); } void DynamicTypeAdvancedTest::XMLCustomizationBySubclassing() { DynAlt o; o.AddAll(); o.UpdateData(); Dyn & p = o.GetSubDyn(); p.AddAll(); p.UpdateData(); bool match = XMLInputOutputMatches(o,__FILE__"DynAlt.xml"); CPPUNIT_ASSERT( match ); } void DynamicTypeAdvancedTest::XMLWithArrayAttribute() { DynWithArrays o; o.AddAll(); o.UpdateData(); Array & af = o.GetMyFloatArray(); af.AddElem(7); af.AddElem(6); af.AddElem(5); af.AddElem(4); af.AddElem(3); af.AddElem(2); af.AddElem(1); af.AddElem(0); Array & ad = o.GetMyDynArray(); Dyn d1; d1.AddAll(); d1.UpdateData(); ad.AddElem(d1); ad.AddElem(d1); ad.AddElem(d1); ad.AddElem(d1); bool match = XMLInputOutputMatches( o,__FILE__"DynWithArrays.xml" ); CPPUNIT_ASSERT( match ); } void DynamicTypeAdvancedTest::XMLWithIterableAttribute() { DynWithIterables o; o.Populate(); o.Modify(5); bool match = XMLInputOutputMatches(o,__FILE__"DynWithIterables.xml"); CPPUNIT_ASSERT( match ); } class Loggable { public: std::string GetLog() { return log.str(); } protected: std::ostringstream log; }; class MyVisitorToInt : public Loggable { public: template void Accept(const char *name, T &value) { Accept(name, value, value); } template void Accept(const char *name, int foo, T& value) { log << "ToInt Visiting '" << name << "' Type int Value: " << value << std::endl; } template void Accept(const char *name, Component &foo, T&value) { log << "ToInt Visiting '" << name << "' Component" << std::endl; } template void Accept(const char *name, DynamicType &foo, T&value) { log << "ToInt Visiting '" << name << "' Dynamic Type" << std::endl; value.VisitAll(*this); } }; class MyVisitorToFloat : public Loggable { public: void Accept(const char *name, float value) { log << "ToFloat Visiting '" << name << "' Type float Value: " << value << std::endl; } void Accept(const char *name, Component &value) { log << "ToFloat Visiting '" << name << "' Component" << std::endl; } }; void DynamicTypeAdvancedTest::VisitorsToPlainDTs() { Dyn p; p.Populate(); p.Modify(4); MyVisitorToInt visitorToInt; p.VisitAll(visitorToInt); CPPUNIT_ASSERT_EQUAL( std::string( "ToInt Visiting 'Int' Type int Value: 4\n" "ToInt Visiting 'MyA' Component\n" "ToInt Visiting 'MyB' Component\n" "ToInt Visiting 'MoreInt' Type int Value: 104\n" "ToInt Visiting 'SubDyn' Dynamic Type\n" ), visitorToInt.GetLog() ); MyVisitorToFloat visitorToFloat; p.VisitAll(visitorToFloat); CPPUNIT_ASSERT_EQUAL( std::string( "ToFloat Visiting 'Int' Type float Value: 4\n" //Notice: float "ToFloat Visiting 'MyA' Component\n" "ToFloat Visiting 'MyB' Component\n" "ToFloat Visiting 'MoreInt' Type float Value: 104\n" //Notice: float "ToFloat Visiting 'SubDyn' Component\n" ), //Notice: Component visitorToFloat.GetLog() ); } void DynamicTypeAdvancedTest::VisitorsToDTWithArrays() { DynWithArrays o; o.Populate(); o.Modify(4); MyVisitorToInt visitorToInt; o.VisitAll(visitorToInt); CPPUNIT_ASSERT_EQUAL( std::string( "ToInt Visiting 'MyFloat' Type int Value: 4\n" "ToInt Visiting 'MyFloatArray' Component\n" "ToInt Visiting 'MyDynArray' Component\n" ), visitorToInt.GetLog() ); MyVisitorToFloat visitorToFloat; o.VisitAll(visitorToFloat); CPPUNIT_ASSERT_EQUAL( std::string( "ToFloat Visiting 'MyFloat' Type float Value: 4\n" //Notice: float "ToFloat Visiting 'MyFloatArray' Component\n" "ToFloat Visiting 'MyDynArray' Component\n" ), visitorToFloat.GetLog() ); } void DynamicTypeAdvancedTest::VisitorsToDTTrees() { DynAlt o; o.Populate(); Dyn & p = o.GetSubDyn(); p.Populate(); p.Modify(5); MyVisitorToInt visitorToInt; o.VisitAll(visitorToInt); CPPUNIT_ASSERT_EQUAL( std::string( "ToInt Visiting 'Int' Type int Value: 0\n" "ToInt Visiting 'MyA' Component\n" "ToInt Visiting 'MyB' Component\n" "ToInt Visiting 'MoreInt' Type int Value: 100\n" "ToInt Visiting 'SubDyn' Dynamic Type\n" "ToInt Visiting 'Int' Type int Value: 5\n" "ToInt Visiting 'MyA' Component\n" "ToInt Visiting 'MyB' Component\n" "ToInt Visiting 'MoreInt' Type int Value: 105\n" "ToInt Visiting 'SubDyn' Dynamic Type\n" ), visitorToInt.GetLog() ); MyVisitorToFloat visitorToFloat; o.VisitAll(visitorToFloat); CPPUNIT_ASSERT_EQUAL( std::string( "ToFloat Visiting 'Int' Type float Value: 0\n" "ToFloat Visiting 'MyA' Component\n" "ToFloat Visiting 'MyB' Component\n" "ToFloat Visiting 'MoreInt' Type float Value: 100\n" "ToFloat Visiting 'SubDyn' Component\n" ), visitorToFloat.GetLog() ); } } //namespace clam-1.4.0/test/UnitTests/DynamicTypeTests/DummyDynamicTypes.hxx0000644000000000000000000002126711101063322023473 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _DummyDynamicTypes_hxx_ #define _DummyDynamicTypes_hxx_ #include #include #include #include "XMLStorage.hxx" // CLAM #include "Component.hxx" // CLAM #include "DynamicType.hxx" // CLAM #include "Array.hxx" // CLAM namespace CLAMTest { ////////////////////////////////////////////////////////////////////// /** * A Dummy Component class with three members of different basic * StoredAsLeaf types members are initiated to 8. */ class CompWithBasics8 : public CLAM::Component { private: static bool sTraceStatus; public: int mA; float mB; double mC; void f() {}; static void Trace(bool status) { sTraceStatus=status; } CompWithBasics8() : mA(8), mB(8), mC(8) { if (sTraceStatus) std::cout << "Constructor CompWithBasics8 at " << this << std::endl; } CompWithBasics8(const CompWithBasics8& arg) : mA(arg.mA), mB(arg.mB), mC(arg.mC) { if (sTraceStatus) std::cout << "Constructor CompWithBasics8 at "<< this << " copying from argument at : " << &arg << std::endl; } ~CompWithBasics8() { if (sTraceStatus) std::cout << "Destructor CompWithBasics8 at "<< this << std::endl; } void StoreOn(CLAM::Storage & storage) const { CLAM::XMLAdapter adaptera(mA, "CWB8a", true); storage.Store(adaptera); CLAM::XMLAdapter adapterb(mB, "CWB8b", true); storage.Store(adapterb); CLAM::XMLAdapter adapterc(mC, "CWB8c", true); storage.Store(adapterc); } void LoadFrom(CLAM::Storage & storage) { CLAM::XMLAdapter adaptera(mA, "CWB8a", true); CLAM_ASSERT(storage.Load(adaptera), "Failed to load CompWithBasics8 item a"); CLAM::XMLAdapter adapterb(mB, "CWB8b", true); CLAM_ASSERT(storage.Load(adapterb), "Failed to load CompWithBasics8 item b"); CLAM::XMLAdapter adapterc(mC, "CWB8c", true); CLAM_ASSERT(storage.Load(adapterc), "Failed to load CompWithBasics8 item c"); } const char* GetClassName() const { return "CompWithBasics8"; } }; ////////////////////////////////////////////////////////////////////// /** * A CompWithBasics8 subclass that puts its members a value of * 9 instead 8. */ class CompWithBasics9 : public CompWithBasics8 { private: static bool sTraceStatus; public: static void Trace(bool status) { sTraceStatus=status; } public: CompWithBasics9() { mA=9; mB=9; mC=9; if (sTraceStatus) std::cout << "Constructor CompWithBasics9 at " << this << std::endl; } CompWithBasics9(const CompWithBasics9 & arg) { mA=arg.mA; mB=arg.mB; mC=arg.mC; if (sTraceStatus) std::cout << "Constructor CompWithBasics9 at " << this << " from argument at " << &arg << std::endl; } ~CompWithBasics9() { if (sTraceStatus) std::cout << "Destructor CompWithBasics9 at " << this << std::endl; } void StoreOn(CLAM::Storage & storage) const { CLAM::XMLAdapter adaptera(mA, "CWB9a", true); storage.Store(adaptera); CLAM::XMLAdapter adapterb(mB, "CWB9b", true); storage.Store(adapterb); CLAM::XMLAdapter adapterc(mC, "CWB9c", true); storage.Store(adapterc); } void LoadFrom(CLAM::Storage & storage) { CLAM::XMLAdapter adaptera(mA, "CWB9a", true); CLAM_ASSERT(storage.Load(adaptera), "Failed to load CompWithBasics8 item a"); CLAM::XMLAdapter adapterb(mB, "CWB9b", true); CLAM_ASSERT(storage.Load(adapterb), "Failed to load CompWithBasics8 item b"); CLAM::XMLAdapter adapterc(mC, "CWB9c", true); CLAM_ASSERT(storage.Load(adapterc), "Failed to load CompWithBasics8 item c"); } }; // Dyn: A dynamicType contaning A and B as DynAttributes class Dyn : public CLAM::DynamicType { private: static bool sTraceStatus; public: static void Trace(bool status) { sTraceStatus=status; } public: DYNAMIC_TYPE(Dyn, 5); DYN_ATTRIBUTE(0, public, int, Int); DYN_ATTRIBUTE(1, public, CompWithBasics8, MyA); DYN_ATTRIBUTE(2, public, CompWithBasics9, MyB); DYN_ATTRIBUTE(3, public, int, MoreInt); DYN_ATTRIBUTE(4, public, Dyn, SubDyn); public: virtual ~Dyn() { if (sTraceStatus) std::cout << "Deleting a Dyn at " << this << std::endl; } public: void Populate() { AddAll(); UpdateData(); GetInt()=0; GetMoreInt()=100; } void Modify(int changeValue) { GetInt()+=changeValue; GetMoreInt()+=changeValue; } }; /** * This class is like the Dyn but it is stored in a diferent way. */ class DynAlt : public Dyn { private: static bool sTraceStatus; public: static void Trace(bool status) { sTraceStatus=status; } virtual ~DynAlt() { if (sTraceStatus) std::cout << "Deleting a DynAlt at " << this << std::endl; } void StoreOn(CLAM::Storage & storage) const { // This Attribute is changed in order StoreSubDyn(storage); // MyA is left StoreMyB(storage); // MyInt is stored as an attribute (the default is element // and adifferent name. if (HasMoreInt()) { CLAM::XMLAdapter adapter(GetMoreInt(), "Size", false); storage.Store(adapter); } // An extra item std::string added = "AddedContent"; CLAM::XMLAdapter adapter(added, "Added", false); storage.Store(adapter); } void LoadFrom(CLAM::Storage & storage) { AddAll(); UpdateData(); // This Attribute is changed in order LoadSubDyn( storage ); // MyA is left LoadMyB( storage ); // MyInt is stored as an attribute (the default is element // and adifferent name. { CLAM::XMLAdapter adapter(GetMoreInt(), "Size", false); if (!storage.Load(adapter)) { RemoveMoreInt(); } } // An extra item { std::string dummy; CLAM::XMLAdapter adapter(dummy, "Added", false); CLAM_ASSERT(storage.Load(adapter), "The additional parameter was not pressent"); } } }; /** * A dynamic type containing as dyn attributes components Array and a * basic type (float) Array. */ class DynWithArrays : public CLAM::DynamicType { public: DYNAMIC_TYPE(DynWithArrays, 3); DYN_ATTRIBUTE(0, public, float, MyFloat); DYN_ATTRIBUTE(1, public, CLAM::Array, MyFloatArray); DYN_ATTRIBUTE(2, public, CLAM::Array, MyDynArray); private: void DefaultInit() { AddAll(); UpdateData(); } public: void Populate() { GetMyFloat()=0; AddAll(); UpdateData(); CLAM::Array &vf = GetMyFloatArray(); CLAM::Array &vd = GetMyDynArray(); for (int i=9; i--;) { vf.AddElem( float(i) ); Dyn d; d.Populate(); d.Modify(i); vd.AddElem(d); } } void Modify(int changeValue) { AddAll(); UpdateData(); CLAM::Array &vf = GetMyFloatArray(); unsigned int i; for (i=vf.Size(); i--;) { vf[i]+=changeValue; } CLAM::Array &vd = GetMyDynArray(); for (i=vd.Size(); i--; ) { vd[i].Modify(changeValue); } GetMyFloat()+=changeValue; } }; /** * A dynamic type containing as dyn attributes components Array and a * basic type (float) Array. */ class DynWithIterables : public CLAM::DynamicType { public: DYNAMIC_TYPE(DynWithIterables, 3); DYN_ATTRIBUTE(0, public, float, MyFloat); DYN_CONTAINER_ATTRIBUTE(1, public, std::vector, MyFloatVector, notused); DYN_CONTAINER_ATTRIBUTE(2, public, std::vector, MyDynVector, aDyn); private: void DefaultInit() { AddAll(); UpdateData(); } public: void Populate() { GetMyFloat()=0; AddAll(); UpdateData(); std::vector &vf = GetMyFloatVector(); std::vector &vd = GetMyDynVector(); for (int i=9; i--;) { vf.push_back( float(i) ); Dyn d; d.Populate(); d.Modify(i); vd.push_back(d); } } void Modify(int changeValue) { AddAll(); UpdateData(); std::vector &vf = GetMyFloatVector(); std::vector::iterator itf = vf.begin(); for (; itf!= vf.end(); itf++) { *itf+=changeValue; } std::vector &vd = GetMyDynVector(); std::vector::iterator itd = vd.begin(); for (; itd != vd.end(); itd++) { itd->Modify(changeValue); } GetMyFloat()+=changeValue; } }; }//namespace CLAMTest #endif clam-1.4.0/test/UnitTests/DynamicTypeTests/DynamicTypeBasicTest.cxx0000644000000000000000000001716110610720021024067 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "DynamicType.hxx" // CLAM #include "DummyDynamicTypes.hxx" namespace CLAMTest { // forward declaration: class DynamicTypeBasicTest; CPPUNIT_TEST_SUITE_REGISTRATION( DynamicTypeBasicTest ); class DynamicTypeBasicTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( DynamicTypeBasicTest ); CPPUNIT_TEST( InstantiateAttributes ); CPPUNIT_TEST( RepetitiveOperations ); CPPUNIT_TEST( NonUpdatedAddsAndRemoves ); CPPUNIT_TEST( ChainedMethods ); CPPUNIT_TEST( ShallowDataAccess ); CPPUNIT_TEST( ShallowDeletion ); CPPUNIT_TEST( DeepDataAccess ); // We would like to have the following test, but valid // accessors are managed with breakpoints, not exceptions. // CPPUNIT_TEST_EXCEPTION( InvalidAccessors, Err ); CPPUNIT_TEST( CopyConstructor ); CPPUNIT_TEST( DeepCopy ); CPPUNIT_TEST( Assignation ); CPPUNIT_TEST( Assignation_WhenIsNotUpdated ); CPPUNIT_TEST( Assignation_WhenIsSelfAssigning ); CPPUNIT_TEST_SUITE_END(); public: // implementation of TestFixture interface void setUp() { dyn = new Dyn; } void tearDown() { delete dyn; } private: Dyn * dyn; // Unit tests: void InstantiateAttributes () { dyn->AddInt(); dyn->AddMyA(); CPPUNIT_ASSERT( !dyn->HasInt() && !dyn->HasMyB() && !dyn->HasInt() ); dyn->UpdateData(); CPPUNIT_ASSERT( dyn->HasInt() && dyn->HasMyA() && !dyn->HasMyB() ); dyn->FullfilsInvariant(); } void RepetitiveOperations() { CPPUNIT_ASSERT( !dyn->HasInt() ); dyn->AddInt(); dyn->AddInt(); CPPUNIT_ASSERT( !dyn->HasInt()&& !dyn->HasMyA() ); dyn->UpdateData(); dyn->RemoveInt(); dyn->RemoveInt(); CPPUNIT_ASSERT( !dyn->HasInt() ); dyn->UpdateData(); CPPUNIT_ASSERT( !dyn->HasInt() ); dyn->FullfilsInvariant(); } void NonUpdatedAddsAndRemoves () { CPPUNIT_ASSERT( !dyn->HasInt() ); dyn->AddInt(); dyn->UpdateData(); CPPUNIT_ASSERT( dyn->HasInt() ); dyn->GetInt() = 777; CPPUNIT_ASSERT( dyn->GetInt() == 777 ); dyn->RemoveInt(); CPPUNIT_ASSERT( !dyn->HasInt() ); dyn->AddInt(); CPPUNIT_ASSERT( dyn->HasInt() ); //Notice: UpdateData() hasn't been necessary. CPPUNIT_ASSERT( dyn->GetInt() == 777 ); dyn->FullfilsInvariant(); } void ChainedMethods () { dyn->AddAll(); CPPUNIT_ASSERT( !dyn->HasInt() && !dyn->HasMyA() && !dyn->HasMyB() ); dyn->UpdateData(); CPPUNIT_ASSERT( dyn->HasInt() && dyn->HasMyA() && dyn->HasMyB() ); dyn->RemoveAll(); CPPUNIT_ASSERT( !dyn->HasInt() && !dyn->HasMyA() && !dyn->HasMyB() ); dyn->UpdateData(); CPPUNIT_ASSERT( !dyn->HasInt() && !dyn->HasMyA() && !dyn->HasMyB() ); dyn->FullfilsInvariant(); } void ShallowDataAccess () { const double delta = 0.00000001; // for doubles equal dyn->AddAll(); dyn->UpdateData(); dyn->SetInt( 5 ); CPPUNIT_ASSERT_EQUAL( 5, dyn->GetInt() ); dyn->GetInt() = 9; CPPUNIT_ASSERT_EQUAL( 9, dyn->GetInt() ); CompWithBasics8 dummyA; dummyA.mA = -2; dummyA.mB = float( 3.1415 ); dummyA.mC = double( 0.123456789 ); dyn->SetMyA( dummyA ); CPPUNIT_ASSERT_EQUAL( -2, dyn->GetMyA().mA ); CPPUNIT_ASSERT_DOUBLES_EQUAL( 3.1415, dyn->GetMyA().mB, delta); CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.123456789, dyn->GetMyA().mC, delta ); dyn->GetMyB().mA = -1; CompWithBasics9 dummyB( dyn->GetMyB() ); CPPUNIT_ASSERT_EQUAL( -1, dummyB.mA ); dyn->FullfilsInvariant(); } void ShallowDeletion () { Dyn *p = new Dyn; CPPUNIT_ASSERT( p ); dyn->FullfilsInvariant(); delete p; } void DeepDataAccess () { dyn->AddAll(); dyn->UpdateData(); dyn->SetInt( 1 ); CPPUNIT_ASSERT( !dyn->GetSubDyn().HasInt() ); Dyn *p = &(dyn->GetSubDyn()); p->AddAll(); p->UpdateData(); CPPUNIT_ASSERT( dyn->GetSubDyn().HasInt() ); p->SetInt( 2 ); p = &(p->GetSubDyn()); p->AddAll(); p->UpdateData(); p->SetInt( 3 ); p = &(dyn->GetSubDyn()); // start over to read. CPPUNIT_ASSERT_EQUAL( 2, p->GetInt() ); p = &(p->GetSubDyn()); CPPUNIT_ASSERT_EQUAL( 3, p->GetInt() ); p = &(p->GetSubDyn()); CPPUNIT_ASSERT( !p->HasInt() ); p->FullfilsInvariant(); dyn->FullfilsInvariant(); } void CopyConstructor() { dyn->AddInt(); dyn->AddSubDyn(); dyn->UpdateData(); dyn->SetInt( 9 ); Dyn foo; foo.AddInt(); foo.UpdateData(); foo.SetInt( 10 ); dyn->SetSubDyn( foo ); Dyn *dynCopy = new Dyn( *dyn ); CPPUNIT_ASSERT( !dynCopy->HasMoreInt() ); CPPUNIT_ASSERT( dynCopy->HasInt() ); CPPUNIT_ASSERT_EQUAL( 9, dynCopy->GetInt()); CPPUNIT_ASSERT( !dynCopy->GetSubDyn().HasSubDyn() ); CPPUNIT_ASSERT( dynCopy->GetSubDyn().HasInt() ); CPPUNIT_ASSERT_EQUAL( 10, dynCopy->GetSubDyn().GetInt() ); dynCopy->GetSubDyn().SetInt(-1); CPPUNIT_ASSERT_EQUAL( 10, dyn->GetSubDyn().GetInt() ); dynCopy->FullfilsInvariant(); delete dynCopy; } void DeepCopy() { // the same test as before but copying with explicit DeepCopy dyn->AddInt(); dyn->AddSubDyn(); dyn->UpdateData(); dyn->SetInt( 9 ); Dyn foo; foo.AddInt(); foo.UpdateData(); foo.SetInt( 10 ); dyn->SetSubDyn( foo ); Dyn *dynCopy = dynamic_cast( dyn->DeepCopy() ); CPPUNIT_ASSERT( !dynCopy->HasMoreInt() ); CPPUNIT_ASSERT( dynCopy->HasInt() ); CPPUNIT_ASSERT_EQUAL( 9, dynCopy->GetInt()); CPPUNIT_ASSERT( !dynCopy->GetSubDyn().HasSubDyn() ); CPPUNIT_ASSERT( dynCopy->GetSubDyn().HasInt() ); CPPUNIT_ASSERT_EQUAL( 10, dynCopy->GetSubDyn().GetInt() ); dynCopy->GetSubDyn().SetInt(-1); CPPUNIT_ASSERT_EQUAL( 10, dyn->GetSubDyn().GetInt() ); dyn->FullfilsInvariant(); dynCopy->FullfilsInvariant(); delete dynCopy; } void Assignation() { // the same as before, now using an operator= dyn->AddInt(); dyn->AddSubDyn(); dyn->UpdateData(); dyn->SetInt( 9 ); Dyn foo; foo.AddInt(); foo.UpdateData(); foo.SetInt( 10 ); dyn->SetSubDyn( foo ); Dyn dynCopyPointee = *dyn; // this extra variable is for keeping cut&paste // compatibility with the last tests. Dyn *dynCopy = &dynCopyPointee; CPPUNIT_ASSERT( !dynCopy->HasMoreInt() ); CPPUNIT_ASSERT( dynCopy->HasInt() ); CPPUNIT_ASSERT_EQUAL( 9, dynCopy->GetInt()); CPPUNIT_ASSERT( !dynCopy->GetSubDyn().HasSubDyn() ); CPPUNIT_ASSERT( dynCopy->GetSubDyn().HasInt() ); CPPUNIT_ASSERT_EQUAL( 10, dynCopy->GetSubDyn().GetInt() ); dynCopy->GetSubDyn().SetInt(-1); CPPUNIT_ASSERT_EQUAL( 10, dyn->GetSubDyn().GetInt() ); // don't delete dynCopy, now: the copy object is a local variable. } void Assignation_WhenIsNotUpdated() { dyn->AddInt(); dyn->AddSubDyn(); dyn->UpdateData(); Dyn foo; dyn->SetSubDyn( foo ); dyn->RemoveSubDyn(); try { Dyn dynCopyPointee = *dyn; CPPUNIT_FAIL("non updated copy should have asserted"); } catch( CLAM::ErrAssertionFailed& ) {} } void Assignation_WhenIsSelfAssigning() { dyn->AddInt(); dyn->UpdateData(); dyn->SetInt(1); *dyn = *dyn; CPPUNIT_ASSERT_EQUAL( 1, dyn->GetInt() ); } }; // class DynamicTypeBasicTest } //namespace clam-1.4.0/test/UnitTests/DynamicTypeTests/DynamicTypeAdvancedTest.hxx0000644000000000000000000000346110630505361024570 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _DynamicTypeAdvancedTest_hxx_ #define _DynamicTypeAdvancedTest_hxx_ #include #include "DynamicType.hxx" // CLAM #include "DummyDynamicTypes.hxx" namespace CLAMTest { class DynamicTypeAdvancedTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( DynamicTypeAdvancedTest ); CPPUNIT_TEST( SimpleXMLSupport ); CPPUNIT_TEST( XMLCustomizationByRedefinition ); CPPUNIT_TEST( XMLCustomizationBySubclassing ); CPPUNIT_TEST( XMLWithArrayAttribute ); CPPUNIT_TEST( XMLWithIterableAttribute ); CPPUNIT_TEST( VisitorsToPlainDTs ); CPPUNIT_TEST( VisitorsToDTWithArrays ); CPPUNIT_TEST( VisitorsToDTTrees ); CPPUNIT_TEST_SUITE_END(); public: void setUp() {}; void tearDown() {}; private: void SimpleXMLSupport(); void XMLCustomizationByRedefinition(); void XMLCustomizationBySubclassing(); void XMLWithArrayAttribute(); void XMLWithIterableAttribute(); void VisitorsToPlainDTs(); void VisitorsToDTWithArrays(); void VisitorsToDTTrees(); }; } // namespace #endif clam-1.4.0/test/UnitTests/StandardTests/0000755000000000000000000000000011344231435016632 5ustar rootrootclam-1.4.0/test/UnitTests/StandardTests/ArrayTest.cxx0000644000000000000000000002572410610720021021273 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "Array.hxx" // CLAM namespace CLAMTest { class ArrayTest; CPPUNIT_TEST_SUITE_REGISTRATION( ArrayTest ); class ArrayTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ArrayTest ); CPPUNIT_TEST( test_Array_Constructor_NonMemoryOwning_With_Null_Pointer ); CPPUNIT_TEST( test_Array_Constructor_NonMemoryOwning_With_Valid_Pointer ); CPPUNIT_TEST( test_Array_CopyOperator_MemoryOwning_Into_MemoryOwning ); CPPUNIT_TEST( test_Array_CopyOperator_Being_The_Array_The_Placeholder_For_A_WriteStreamRegion ); CPPUNIT_TEST( test_SetPtr_OnEmptyArray ); CPPUNIT_TEST( test_TwoConsecutiveSetPtrs_OnEmptyArray ); CPPUNIT_TEST( test_SetPtr_OnNonEmptyArray ); CPPUNIT_TEST( test_Resize_To_Zero_Flushes_The_Array ); CPPUNIT_TEST( test_Resize_To_Negative_Triggers_Assertion_Failure ); CPPUNIT_TEST( test_GiveChunk_OutOfBounds_Chunk_Triggers_Assertion ); CPPUNIT_TEST( test_CopyChunk_OutOfBounds_Chunk_Triggers_Assertion ); CPPUNIT_TEST( test_CopyChunk_Legal_Chunk_On_Empty_Array_Triggers_Assertion ); CPPUNIT_TEST( test_Add_Element_To_Beginning_Of_Array ); CPPUNIT_TEST( test_Add_Element_To_End_Of_Array ); CPPUNIT_TEST( test_Add_Element_To_Middle_Of_Array ); CPPUNIT_TEST( test_Delete_Element_From_Beginning_Of_Array ); CPPUNIT_TEST( test_Delete_Element_From_End_Of_Array ); CPPUNIT_TEST( test_Delete_Element_From_Middle_Of_Array ); CPPUNIT_TEST( test_Add_Element_To_Empty_Array ); CPPUNIT_TEST( test_Insert_Element_Into_Empty_Array ); CPPUNIT_TEST( test_Delete_Element_From_Empty_Array ); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: void test_SetPtr_OnEmptyArray() { int buffer[] = { 1, 2, 3, 4}; CLAM::Array array; array.SetPtr( buffer, 4 ); CPPUNIT_ASSERT( !array.OwnsMemory() ); CPPUNIT_ASSERT( array.Size() == 4 ); CPPUNIT_ASSERT( array.GetPtr() == buffer ); } void test_TwoConsecutiveSetPtrs_OnEmptyArray() { int buffer[] = { 1, 2, 3, 4}; CLAM::Array array; array.SetPtr( buffer, 4 ); int buffer2[] = { 1, 2, 3, 4, 5, 6 }; array.SetPtr( buffer2, 6 ); CPPUNIT_ASSERT( !array.OwnsMemory() ); CPPUNIT_ASSERT( array.Size() == 6 ); CPPUNIT_ASSERT( array.GetPtr() == buffer2 ); } void test_SetPtr_OnNonEmptyArray() { int buffer[] = { 1, 2, 3, 4}; CLAM::Array array; array.Resize( 4 ); array.SetSize( 4 ); try { array.SetPtr( buffer, 4 ); } catch( CLAM::ErrAssertionFailed& e ) { return; } CPPUNIT_FAIL( "Array::SetPtr() on Memory Owning, non-empty Array must raise and assertion failure" ); } void test_Array_Constructor_NonMemoryOwning_With_Valid_Pointer() { int buffer[] = { 1, 2, 3, 4}; CLAM::Array array( buffer, 4 ); CPPUNIT_ASSERT( !array.OwnsMemory() ); CPPUNIT_ASSERT( array.Size() == 4 ); CPPUNIT_ASSERT( array.GetPtr() == buffer ); } void test_Array_Constructor_NonMemoryOwning_With_Null_Pointer() { try { CLAM::Array array( (int*)NULL, 0 ); } catch( CLAM::ErrAssertionFailed& e ) { return; } CPPUNIT_FAIL("Invoking the Array::Array( T*, int) constructor passing a " "NULL pointer should have triggered an assertion failure!"); } void test_Array_CopyOperator_MemoryOwning_Into_MemoryOwning() { CLAM::DataArray src; src.Resize( 10 ); src.SetSize( 10 ); for ( int i = 0; i < src.Size(); i++ ) src[i] = i; CLAM::DataArray dst; dst.Resize( 10 ); dst.SetSize( 10 ); dst = src; bool sizeItsTheSame = ( src.Size() == dst.Size() ); bool dstDoesOwnMemory = dst.OwnsMemory(); bool allElemsEqual = true; for ( int i = 0; i < dst.Size(); i++ ) { allElemsEqual &= ( dst[i] == i ); } CPPUNIT_ASSERT( allElemsEqual ); CPPUNIT_ASSERT( sizeItsTheSame ); CPPUNIT_ASSERT( dstDoesOwnMemory ); } void test_Array_CopyOperator_Being_The_Array_The_Placeholder_For_A_WriteStreamRegion() { CLAM::Array streamBuffer; streamBuffer.Resize(4); streamBuffer.SetSize(4); streamBuffer[0] = 1; streamBuffer[1] = 2; streamBuffer[2] = 3; streamBuffer[3] = 4; CLAM::Array array; streamBuffer.GiveChunk( 1, 2, array ); CLAM::Array data; data.Resize(2); data.SetSize(2); array = data; CPPUNIT_ASSERT( streamBuffer[0] == 1 ); CPPUNIT_ASSERT( streamBuffer[1] == 0 ); CPPUNIT_ASSERT( streamBuffer[2] == 0 ); CPPUNIT_ASSERT( streamBuffer[3] == 4 ); } void test_Resize_To_Zero_Flushes_The_Array() { CLAM::Array array; //Unused variable: const int* oldPointer = array.GetPtr(); array.Resize( 0 ); CPPUNIT_ASSERT( array.GetPtr() == NULL ); CPPUNIT_ASSERT( array.Size() == 0 ); CPPUNIT_ASSERT( array.AllocatedSize() == 0 ); CPPUNIT_ASSERT( array.Empty() == true ); } void test_Resize_To_Negative_Triggers_Assertion_Failure() { CLAM::Array array; try { array.Resize( -150 ); } catch( CLAM::ErrAssertionFailed& e ) { return; } CPPUNIT_FAIL( "Array::Resize( int ) : with negative arguments should have triggered " "an assertion failure."); } void test_GiveChunk_OutOfBounds_Chunk_Triggers_Assertion() { CLAM::Array array; array.Resize(10); array.SetSize( 10 ); CLAM::Array chunkReceiver; try { array.GiveChunk( 5, 25, chunkReceiver ); } catch( CLAM::ErrAssertionFailed& e ) { return; } CPPUNIT_FAIL( "Array::GiveChunk() : when chunk offset plus length surpasses array logical size " "an assertion failure should be raised."); } void test_CopyChunk_OutOfBounds_Chunk_Triggers_Assertion() { CLAM::Array array; array.Resize(10); array.SetSize( 10 ); CLAM::Array chunkReceiver; chunkReceiver.Resize( 20 ); chunkReceiver.SetSize( 20 ); try { array.CopyChunk( 5, 25, chunkReceiver ); } catch( CLAM::ErrAssertionFailed& e ) { return; } CPPUNIT_FAIL( "Array::CopyChunk() : when chunk offset plus length surpasses array logical size " "an assertion failure should be raised."); } void test_CopyChunk_Legal_Chunk_On_Empty_Array_Triggers_Assertion() { CLAM::Array array; array.Resize(10); array.SetSize( 10 ); CLAM::Array chunkReceiver; try { array.CopyChunk( 5, 25, chunkReceiver ); } catch( CLAM::ErrAssertionFailed& e ) { return; } CPPUNIT_FAIL( "Array::CopyChunk() : destination array is expected to own ( or point to ) " "a large enough pool of memory, but no assertion failure has been raised "); } void test_Add_Element_To_Beginning_Of_Array() { CLAM::Array testArray; testArray.Resize( 4 ); testArray.SetSize( 4 ); testArray[0] = 1; testArray[1] = 2; testArray[2] = 3; testArray[3] = 4; testArray.InsertElem( 0, 0 ); CPPUNIT_ASSERT( testArray.Size() == 5 ); CPPUNIT_ASSERT( testArray.AllocatedSize() == 5 ); CPPUNIT_ASSERT( testArray.OwnsMemory() == true ); CPPUNIT_ASSERT( testArray[0] == 0 ); CPPUNIT_ASSERT( testArray[1] == 1 ); CPPUNIT_ASSERT( testArray[2] == 2 ); CPPUNIT_ASSERT( testArray[3] == 3 ); CPPUNIT_ASSERT( testArray[4] == 4 ); } void test_Add_Element_To_End_Of_Array() { CLAM::Array testArray; testArray.Resize( 4 ); testArray.SetSize( 4 ); testArray[0] = 1; testArray[1] = 2; testArray[2] = 3; testArray[3] = 4; testArray.AddElem( 5 ); CPPUNIT_ASSERT( testArray.Size() == 5 ); CPPUNIT_ASSERT( testArray.AllocatedSize() == 5 ); CPPUNIT_ASSERT( testArray.OwnsMemory() == true ); CPPUNIT_ASSERT( testArray[0] == 1 ); CPPUNIT_ASSERT( testArray[1] == 2 ); CPPUNIT_ASSERT( testArray[2] == 3 ); CPPUNIT_ASSERT( testArray[3] == 4 ); CPPUNIT_ASSERT( testArray[4] == 5 ); } void test_Add_Element_To_Middle_Of_Array() { CLAM::Array testArray; testArray.Resize( 4 ); testArray.SetSize( 4 ); testArray[0] = 1; testArray[1] = 3; testArray[2] = 4; testArray[3] = 5; testArray.InsertElem( 1, 2 ); CPPUNIT_ASSERT( testArray.Size() == 5 ); CPPUNIT_ASSERT( testArray.AllocatedSize() == 5 ); CPPUNIT_ASSERT( testArray.OwnsMemory() == true ); CPPUNIT_ASSERT( testArray[0] == 1 ); CPPUNIT_ASSERT( testArray[1] == 2 ); CPPUNIT_ASSERT( testArray[2] == 3 ); CPPUNIT_ASSERT( testArray[3] == 4 ); CPPUNIT_ASSERT( testArray[4] == 5 ); } void test_Delete_Element_From_Beginning_Of_Array() { CLAM::Array testArray; testArray.Resize( 4 ); testArray.SetSize( 4 ); testArray[0] = 1; testArray[1] = 2; testArray[2] = 3; testArray[3] = 4; const int* oldPtr = testArray.GetPtr(); testArray.DeleteElem( 0 ); CPPUNIT_ASSERT( oldPtr == testArray.GetPtr() ); CPPUNIT_ASSERT( testArray.Size() == 3 ); CPPUNIT_ASSERT( testArray.AllocatedSize() == 4 ); CPPUNIT_ASSERT( testArray.OwnsMemory() == true ); CPPUNIT_ASSERT( testArray[0] == 2 ); CPPUNIT_ASSERT( testArray[1] == 3 ); CPPUNIT_ASSERT( testArray[2] == 4 ); } void test_Delete_Element_From_End_Of_Array() { CLAM::Array testArray; testArray.Resize( 4 ); testArray.SetSize( 4 ); testArray[0] = 1; testArray[1] = 2; testArray[2] = 3; testArray[3] = 4; const int* oldPtr = testArray.GetPtr(); testArray.DeleteElem( testArray.Size() - 1 ); CPPUNIT_ASSERT( testArray.GetPtr() == oldPtr ); CPPUNIT_ASSERT( testArray.Size() == 3 ); CPPUNIT_ASSERT( testArray.AllocatedSize() == 4 ); CPPUNIT_ASSERT( testArray.OwnsMemory() == true ); CPPUNIT_ASSERT( testArray[0] == 1 ); CPPUNIT_ASSERT( testArray[1] == 2 ); CPPUNIT_ASSERT( testArray[2] == 3 ); } void test_Delete_Element_From_Middle_Of_Array() { CLAM::Array testArray; testArray.Resize( 4 ); testArray.SetSize( 4 ); testArray[0] = 1; testArray[1] = 2; testArray[2] = 3; testArray[3] = 4; const int* oldPtr = testArray.GetPtr(); testArray.DeleteElem( 1 ); CPPUNIT_ASSERT( testArray.GetPtr() == oldPtr ); CPPUNIT_ASSERT( testArray.Size() == 3 ); CPPUNIT_ASSERT( testArray.AllocatedSize() == 4 ); CPPUNIT_ASSERT( testArray.OwnsMemory() == true ); CPPUNIT_ASSERT( testArray[0] == 1 ); CPPUNIT_ASSERT( testArray[1] == 3 ); CPPUNIT_ASSERT( testArray[2] == 4 ); } void test_Add_Element_To_Empty_Array() { CLAM::Array testArray; testArray.AddElem( 33 ); CPPUNIT_ASSERT( testArray[0] == 33 ); CPPUNIT_ASSERT( testArray.Empty() == false ); CPPUNIT_ASSERT( testArray.Size() == 1 ); CPPUNIT_ASSERT( testArray.AllocatedSize() == 1 ); CPPUNIT_ASSERT( testArray.OwnsMemory() == true ); } void test_Insert_Element_Into_Empty_Array() { CLAM::Array testArray; try { testArray.InsertElem( 0, 33 ); } catch( CLAM::ErrAssertionFailed& e ) { return; } CPPUNIT_FAIL( "Array::InsertElem() : This method cannot be used on empty arrays, so an assertion " "should have been raised"); } void test_Delete_Element_From_Empty_Array() { CLAM::Array testArray; try { testArray.DeleteElem( 0 ); } catch( CLAM::ErrAssertionFailed& e ) { return; } CPPUNIT_FAIL( "Array::DeleteElem() : deleting an element from an empty array should fail " ); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/StandardTests/SearchArrayTest.cxx0000644000000000000000000000564210610720021022416 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "SearchArray.hxx" // CLAM #include "stl_optbinsearch.h" // CLAM #include "Array.hxx" // CLAM #include "Point.hxx" // CLAM namespace CLAM_Math { struct compareX { bool operator()( const CLAM::Point& lhs, const CLAM::Point& rhs ) { return ( lhs.GetX() >= rhs.GetX() ); } }; class SearchArrayTest; CPPUNIT_TEST_SUITE_REGISTRATION( SearchArrayTest ); class SearchArrayTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( SearchArrayTest ); CPPUNIT_TEST( test_Search_On_Ordered_Array_Of_Points ); CPPUNIT_TEST( test_optbinsearch ); CPPUNIT_TEST( test_optbinsearch_w_pred ); CPPUNIT_TEST_SUITE_END(); public: void setUp() { } void tearDown() { } private: void test_Search_On_Ordered_Array_Of_Points() { CLAM::Array< CLAM::Point > array; CLAM::SearchArray< CLAM::Point > searchArray; array.AddElem( CLAM::Point( 0.0, 2.0 ) ); array.AddElem( CLAM::Point( 1.5, 1.0 ) ); array.AddElem( CLAM::Point( 3.0, 2.0 ) ); searchArray.Set( array ); CLAM::TIndex nearest = searchArray.Find( CLAM::Point( 0.8, 0.0 ), -1 ); CPPUNIT_ASSERT( nearest == 0 ); nearest = searchArray.Find( CLAM::Point( -3.2, 0.0 ), nearest ); CPPUNIT_ASSERT( nearest == -1 ); nearest = searchArray.Find( CLAM::Point( 3.2, 0.0 ), nearest ); CPPUNIT_ASSERT( nearest == 2 ); } void test_optbinsearch() { CLAM::Array< CLAM::Point > array; array.AddElem( CLAM::Point( 0.0, 2.0 ) ); array.AddElem( CLAM::Point( 1.5, 1.0 ) ); array.AddElem( CLAM::Point( 3.0, 2.0 ) ); CLAM::Point* nearest = std::hunt( array.GetPtr(), array.GetPtr()+array.Size(), CLAM::Point( 0.8, 0.0 ) ); CPPUNIT_ASSERT( std::distance( nearest, array.GetPtr() ) == 0 ); nearest = std::hunt( array.GetPtr(), array.GetPtr()+array.Size(), CLAM::Point( -3.2, 0.0 ), nearest ); CPPUNIT_ASSERT( nearest == array.GetPtr()+array.Size() ); nearest = std::hunt( array.GetPtr(), array.GetPtr()+array.Size(), CLAM::Point( 3.2, 0.0 ), nearest ); CPPUNIT_ASSERT( nearest == array.GetPtr()+2 ); } void test_optbinsearch_w_pred() { CLAM::Array< CLAM::Point > array; array.AddElem( CLAM::Point( 0.0, 2.0 ) ); array.AddElem( CLAM::Point( 1.5, 1.0 ) ); array.AddElem( CLAM::Point( 3.0, 2.0 ) ); CLAM::Point* nearest = std::hunt( array.GetPtr(), array.GetPtr()+array.Size(), CLAM::Point( 0.8, 0.0 ), compareX() ); CPPUNIT_ASSERT( std::distance( nearest, array.GetPtr() ) == 0 ); nearest = std::hunt( array.GetPtr(), array.GetPtr()+array.Size(), CLAM::Point( -3.2, 0.0 ), nearest, compareX() ); CPPUNIT_ASSERT( nearest == array.GetPtr()+array.Size() ); nearest = std::hunt( array.GetPtr(), array.GetPtr()+array.Size(), CLAM::Point( 3.2, 0.0 ), nearest, compareX() ); CPPUNIT_ASSERT( nearest == array.GetPtr()+2 ); } }; } clam-1.4.0/test/UnitTests/StandardTests/BPFTest.cxx0000644000000000000000000001704610610720021020622 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "BPF.hxx" // CLAM #include "CLAM_Math.hxx" // CLAM namespace CLAMTest { class BPFTest; CPPUNIT_TEST_SUITE_REGISTRATION( BPFTest ); class BPFTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( BPFTest ); CPPUNIT_TEST( test_After_SetValue_i_Y_GetValue_i_Yields_Y ); CPPUNIT_TEST( test_After_SetValue_0_Y_GetValueFromIndex_0_Yields_Y ); CPPUNIT_TEST( test_Copy_Of_BPFs ); CPPUNIT_TEST( test_Delete_Between_A_Range_Of_X_Values ); CPPUNIT_TEST( test_Delete_Through_X_Value ); CPPUNIT_TEST( test_Insert_X_Y_Pair ); CPPUNIT_TEST( test_Insert_Point ); CPPUNIT_TEST( test_GetValue_Interpolation_Mode_Step ); CPPUNIT_TEST( test_GetValue_Interpolation_Mode_Round ); CPPUNIT_TEST( test_GetValue_Interpolation_Mode_Linear ); CPPUNIT_TEST( test_GetValue_Interpolation_Mode_Quadratic ); CPPUNIT_TEST( test_GetValue_Interpolation_Mode_Spline ); CPPUNIT_TEST_SUITE_END(); public: void setUp() { } void tearDown() { } private: void test_After_SetValue_i_Y_GetValue_i_Yields_Y() { CLAM::BPF bpf; bpf.Resize(2); bpf.SetSize(2); bpf.SetXValue( 0, CLAM::TData(0) ); bpf.SetValue( 0, CLAM::TData(1) ); bpf.SetXValue( 1, CLAM::TData(1) ); bpf.SetValue( 1, CLAM::TData(0) ); CPPUNIT_ASSERT( bpf.GetValue(CLAM::TData(0)) == CLAM::TData(1) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex(0) == CLAM::TData(1) ); CPPUNIT_ASSERT( bpf.GetValue(CLAM::TData(1)) == CLAM::TData(0) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex(1) == CLAM::TData(0) ); } void test_After_SetValue_0_Y_GetValueFromIndex_0_Yields_Y() { CLAM::BPF bpf; bpf.Resize(1); bpf.SetSize(1); bpf.SetValue( 0, CLAM::TData(1) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex(0) == CLAM::TData(1) ); } void test_Copy_Of_BPFs() { CLAM::BPF originalBPF; originalBPF.Resize(5); originalBPF.SetSize(5); originalBPF.SetXValue(0, CLAM::TData(0) ); originalBPF.SetXValue(1, CLAM::TData(1) ); originalBPF.SetXValue(2, CLAM::TData(2) ); originalBPF.SetXValue(3, CLAM::TData(3) ); originalBPF.SetXValue(4, CLAM::TData(4) ); originalBPF.SetValue( 0, CLAM::TData(1) ); originalBPF.SetValue( 1, CLAM::TData(1) ); originalBPF.SetValue( 2, CLAM::TData(1) ); originalBPF.SetValue( 3, CLAM::TData(1) ); originalBPF.SetValue( 4, CLAM::TData(1) ); CLAM::BPF theCopy; theCopy = originalBPF; CPPUNIT_ASSERT( originalBPF.GetXValue(0) == theCopy.GetXValue(0) ); CPPUNIT_ASSERT( originalBPF.GetXValue(1) == theCopy.GetXValue(1) ); CPPUNIT_ASSERT( originalBPF.GetXValue(2) == theCopy.GetXValue(2) ); CPPUNIT_ASSERT( originalBPF.GetXValue(3) == theCopy.GetXValue(3) ); CPPUNIT_ASSERT( originalBPF.GetXValue(4) == theCopy.GetXValue(4) ); CPPUNIT_ASSERT( originalBPF.GetValue(0) == theCopy.GetValue(0) ); CPPUNIT_ASSERT( originalBPF.GetValue(1) == theCopy.GetValue(1) ); CPPUNIT_ASSERT( originalBPF.GetValue(2) == theCopy.GetValue(2) ); CPPUNIT_ASSERT( originalBPF.GetValue(3) == theCopy.GetValue(3) ); CPPUNIT_ASSERT( originalBPF.GetValue(4) == theCopy.GetValue(4) ); } void test_Delete_Through_X_Value() { CLAM::BPF theBPF; theBPF.Resize(3); theBPF.SetSize(3); theBPF.SetXValue( 0, CLAM::TData(0) ); theBPF.SetXValue( 1, CLAM::TData(1) ); theBPF.SetXValue( 2, CLAM::TData(2) ); theBPF.SetValue( 0, CLAM::TData(1) ); theBPF.SetValue( 1, CLAM::TData(1) ); theBPF.SetValue( 2, CLAM::TData(1) ); theBPF.DeleteThroughXValue( CLAM::TData(1) ); CPPUNIT_ASSERT( theBPF.Size() == 2 ); CPPUNIT_ASSERT( theBPF.GetXValue(0) == 0 ); CPPUNIT_ASSERT( theBPF.GetXValue(1) == 2 ); } void test_Delete_Between_A_Range_Of_X_Values() { CLAM::BPF theBPF; theBPF.Resize(5); theBPF.SetSize(5); theBPF.SetXValue(0, CLAM::TData(0) ); theBPF.SetXValue(1, CLAM::TData(1) ); theBPF.SetXValue(2, CLAM::TData(2) ); theBPF.SetXValue(3, CLAM::TData(3) ); theBPF.SetXValue(4, CLAM::TData(4) ); theBPF.SetValue( 0, CLAM::TData(1) ); theBPF.SetValue( 1, CLAM::TData(1) ); theBPF.SetValue( 2, CLAM::TData(1) ); theBPF.SetValue( 3, CLAM::TData(1) ); theBPF.SetValue( 4, CLAM::TData(-1) ); theBPF.DeleteBetweenXValues( CLAM::TData(1), CLAM::TData(3) ); CPPUNIT_ASSERT( theBPF.GetValue(0) == 1 ); CPPUNIT_ASSERT( theBPF.GetValue(4) == -1 ); CPPUNIT_ASSERT( theBPF.GetXValue(0) == 0 ); CPPUNIT_ASSERT( theBPF.GetXValue(1) == 4 ); } void test_Insert_X_Y_Pair() { CLAM::BPF theBPF; theBPF.Resize( 2 ); theBPF.SetSize( 2 ); theBPF.SetXValue( 0, CLAM::TData(0) ); theBPF.SetValue( 0, CLAM::TData( 2 ) ); theBPF.SetXValue( 1, CLAM::TData( 31 ) ); theBPF.SetValue( 1, CLAM::TData( 1.5 ) ); CLAM::TIndex insertedAt = theBPF.Insert( 30.98, 1.75 ); CPPUNIT_ASSERT( theBPF.Size() == 3 ); CPPUNIT_ASSERT( insertedAt == 1 ); } void test_Insert_Point() { CLAM::BPF theBPF; theBPF.Resize( 2 ); theBPF.SetSize( 2 ); theBPF.SetXValue( 0, CLAM::TData(0) ); theBPF.SetValue( 0, CLAM::TData( 2 ) ); theBPF.SetXValue( 1, CLAM::TData( 31 ) ); theBPF.SetValue( 1, CLAM::TData( 1.5 ) ); CLAM::TIndex insertedAt = theBPF.Insert( CLAM::Point(30.98, 1.75) ); CPPUNIT_ASSERT( theBPF.Size() == 3 ); CPPUNIT_ASSERT( insertedAt == 1 ); } void test_GetValue_Interpolation_Mode_Step() { CLAM::BPF theBPF; theBPF.Insert( 0.0, 2.0 ); theBPF.Insert( 1.5, 1.0 ); theBPF.Insert( 3.0, 2.0 ); CLAM::TData interpYa = theBPF.GetValue( 0.8, CLAM::EInterpolation::eStep ); CLAM::TData interpYb = theBPF.GetValue( 2.72, CLAM::EInterpolation::eStep ); CPPUNIT_ASSERT( fabs( interpYa - 2.0 ) <= 1e-7 ); CPPUNIT_ASSERT( fabs( interpYb - 1.0 ) <= 1e-7 ); } void test_GetValue_Interpolation_Mode_Round() { CLAM::BPF theBPF; theBPF.Insert( 0.0, 2.0 ); theBPF.Insert( 1.5, 1.0 ); theBPF.Insert( 3.0, 2.0 ); //CLAM::TData interpYa = theBPF.GetValue( 0.8, CLAM::EInterpolation::eRound ); //CLAM::TData interpYb = theBPF.GetValue( 2.72, CLAM::EInterpolation::eRound ); // :TODO: This is not working properly!! //CPPUNIT_ASSERT( fabs( interpYa - 1.0 ) <= 1e-7 ); //CPPUNIT_ASSERT( fabs( interpYb - 2.0 ) <= 1e-7 ); } void test_GetValue_Interpolation_Mode_Linear() { CLAM::BPF theBPF; theBPF.Insert( 0.0, 2.0 ); theBPF.Insert( 1.5, 1.0 ); theBPF.Insert( 3.0, 2.0 ); CLAM::TData interpYa = theBPF.GetValue( 0.8, CLAM::EInterpolation::eLinear ); CLAM::TData interpYb = theBPF.GetValue( 2.72, CLAM::EInterpolation::eLinear ); CPPUNIT_ASSERT( fabs( interpYa - 1.46667 ) <= 5e-6 ); CPPUNIT_ASSERT( fabs( interpYb - 1.81333 ) <= 5e-6 ); } void test_GetValue_Interpolation_Mode_Quadratic() { CLAM::BPF theBPF; theBPF.Insert( 0.0, 2.0 ); theBPF.Insert( 1.5, 1.0 ); theBPF.Insert( 3.0, 2.0 ); CLAM::TData interpYa = theBPF.GetValue( 0.8, CLAM::EInterpolation::ePolynomial2 ); CLAM::TData interpYb = theBPF.GetValue( 2.72, CLAM::EInterpolation::ePolynomial2 ); CPPUNIT_ASSERT( fabs( interpYa - 1.46667 ) <= 5e-6 ); CPPUNIT_ASSERT( fabs( interpYb - 1.81333 ) <= 5e-6 ); } void test_GetValue_Interpolation_Mode_Spline() { CLAM::BPF theBPF; theBPF.Insert( 0.0, 2.0 ); theBPF.Insert( 1.5, 1.0 ); theBPF.Insert( 3.0, 2.0 ); CLAM::TData interpYa = theBPF.GetValue( 0.8, CLAM::EInterpolation::ePolynomial2 ); CLAM::TData interpYb = theBPF.GetValue( 2.72, CLAM::EInterpolation::ePolynomial2 ); CPPUNIT_ASSERT( fabs( interpYa - 1.46667 ) <= 5e-6 ); CPPUNIT_ASSERT( fabs( interpYb - 1.81333 ) <= 5e-6 ); } }; } clam-1.4.0/test/UnitTests/StandardTests/ArrayToBPFCnvTest.cxx0000644000000000000000000000740510610720021022571 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "Array.hxx" // CLAM #include "BPF.hxx" // CLAM #include "ArrayToBPFCnv.hxx" // CLAM namespace CLAMTest { class ArrayToBPFCnvTest; CPPUNIT_TEST_SUITE_REGISTRATION( ArrayToBPFCnvTest ); class ArrayToBPFCnvTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ArrayToBPFCnvTest ); CPPUNIT_TEST( test_ConvertToBPF_NoXValuesSpecified ); CPPUNIT_TEST( test_ConvertToBPF_XValuesSpecifiedAsStartAndDelta ); CPPUNIT_TEST( test_ConvertToBPF_XValuesInsideAnArray ); CPPUNIT_TEST_SUITE_END(); protected: CLAM::Array mTestXValues; CLAM::Array mTestYValues; public: void setUp() { } void tearDown() { } private: void test_ConvertToBPF_NoXValuesSpecified() { CLAM::BPF bpf; CLAM::TData _xValues[] = {0, 100, 200, 300, 400, 500}; CLAM::TData _yValues[] = {1, 0, 1, 0, 1, 0 }; mTestXValues.SetPtr( _xValues, 6 ); mTestYValues.SetPtr( _yValues, 6 ); bpf.Resize( 6 ); bpf.SetSize( 6 ); CLAM::ConvertToBPF( bpf, mTestYValues ); CPPUNIT_ASSERT( bpf.GetValue( 0 ) == CLAM::TData( 1 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 1 ) == CLAM::TData( 0 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 2 ) == CLAM::TData( 1 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 3 ) == CLAM::TData( 0 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 4 ) == CLAM::TData( 1 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 5 ) == CLAM::TData( 0 ) ); } void test_ConvertToBPF_XValuesSpecifiedAsStartAndDelta() { CLAM::BPF bpf; CLAM::TData _xValues[] = {0, 100, 200, 300, 400, 500}; CLAM::TData _yValues[] = {1, 0, 1, 0, 1, 0 }; mTestXValues.SetPtr( _xValues, 6 ); mTestYValues.SetPtr( _yValues, 6 ); bpf.Resize(6); bpf.SetSize( 6 ); CLAM::ConvertToBPF( bpf, CLAM::TData(0), CLAM::TData(100), mTestYValues ); CPPUNIT_ASSERT( bpf.GetXValue( 0 ) == CLAM::TData(0) ); CPPUNIT_ASSERT( bpf.GetXValue( 1 ) == CLAM::TData(100) ); CPPUNIT_ASSERT( bpf.GetXValue( 2 ) == CLAM::TData(200) ); CPPUNIT_ASSERT( bpf.GetXValue( 3 ) == CLAM::TData(300) ); CPPUNIT_ASSERT( bpf.GetXValue( 4 ) == CLAM::TData(400) ); CPPUNIT_ASSERT( bpf.GetXValue( 5 ) == CLAM::TData(500) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 0 ) == CLAM::TData( 1 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 1 ) == CLAM::TData( 0 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 2 ) == CLAM::TData( 1 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 3 ) == CLAM::TData( 0 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 4 ) == CLAM::TData( 1 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 5 ) == CLAM::TData( 0 ) ); } void test_ConvertToBPF_XValuesInsideAnArray() { CLAM::BPF bpf; bpf.Resize(6); bpf.SetSize(6); CLAM::TData _xValues[] = {0, 100, 200, 300, 400, 500}; CLAM::TData _yValues[] = {1, 0, 1, 0, 1, 0 }; mTestXValues.SetPtr( _xValues, 6 ); mTestYValues.SetPtr( _yValues, 6 ); CLAM::ConvertToBPF( bpf, mTestXValues, mTestYValues ); CPPUNIT_ASSERT( bpf.GetXValue( 0 ) == CLAM::TData(0) ); CPPUNIT_ASSERT( bpf.GetXValue( 1 ) == CLAM::TData(100) ); CPPUNIT_ASSERT( bpf.GetXValue( 2 ) == CLAM::TData(200) ); CPPUNIT_ASSERT( bpf.GetXValue( 3 ) == CLAM::TData(300) ); CPPUNIT_ASSERT( bpf.GetXValue( 4 ) == CLAM::TData(400) ); CPPUNIT_ASSERT( bpf.GetXValue( 5 ) == CLAM::TData(500) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 0 ) == CLAM::TData( 1 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 1 ) == CLAM::TData( 0 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 2 ) == CLAM::TData( 1 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 3 ) == CLAM::TData( 0 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 4 ) == CLAM::TData( 1 ) ); CPPUNIT_ASSERT( bpf.GetValueFromIndex( 5 ) == CLAM::TData( 0 ) ); } }; } clam-1.4.0/test/UnitTests/StandardTests/RulerTicksTest.cxx0000644000000000000000000000557511132120764022316 0ustar rootroot#include #include /* TODO: - */ namespace CLAMTest { class RulerTicksTest; CPPUNIT_TEST_SUITE_REGISTRATION( RulerTicksTest ); class RulerTicksTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE (RulerTicksTest); CPPUNIT_TEST (testOffsetAndGap_withUnitGap); CPPUNIT_TEST (testOffsetAndGap_withHalfWidth); CPPUNIT_TEST (testOffsetAndGap_withMinGap2); CPPUNIT_TEST (testOffsetAndGap_withMinGap3); CPPUNIT_TEST (testOffsetAndGap_withOffsetAndMarkOnOffset); CPPUNIT_TEST (testOffsetAndGap_withOffsetAndMarkNotOnOffset); CPPUNIT_TEST (testOffsetAndGap_withNegativeRange); CPPUNIT_TEST (testOffsetAndGap_withZoomOut); CPPUNIT_TEST (testNTicks); CPPUNIT_TEST_SUITE_END(); private: void testOffsetAndGap_withUnitGap() { CLAM::RulerTicks ruler; ruler.setRange(0,10); ruler.setMinGap(1); ruler.setWidth(10); CPPUNIT_ASSERT_EQUAL(1.0, ruler.markGap()); CPPUNIT_ASSERT_EQUAL(0.0, ruler.markOffset()); } void testOffsetAndGap_withHalfWidth() { CLAM::RulerTicks ruler; ruler.setRange(0,10); ruler.setMinGap(1); ruler.setWidth(5); CPPUNIT_ASSERT_EQUAL(2.0, ruler.markGap()); CPPUNIT_ASSERT_EQUAL(0.0, ruler.markOffset()); } void testOffsetAndGap_withMinGap2() { CLAM::RulerTicks ruler; ruler.setRange(0,10); ruler.setMinGap(2); ruler.setWidth(10); CPPUNIT_ASSERT_EQUAL(2.0, ruler.markGap()); CPPUNIT_ASSERT_EQUAL(0.0, ruler.markOffset()); } void testOffsetAndGap_withMinGap3() { CLAM::RulerTicks ruler; ruler.setRange(0,10); ruler.setMinGap(3); ruler.setWidth(10); CPPUNIT_ASSERT_EQUAL(5.0, ruler.markGap()); CPPUNIT_ASSERT_EQUAL(0.0, ruler.markOffset()); } void testOffsetAndGap_withOffsetAndMarkOnOffset() { CLAM::RulerTicks ruler; ruler.setRange(2,12); ruler.setMinGap(1); ruler.setWidth(10); CPPUNIT_ASSERT_EQUAL(1.0, ruler.markGap()); CPPUNIT_ASSERT_EQUAL(2.0, ruler.markOffset()); } void testOffsetAndGap_withNegativeRange() { CLAM::RulerTicks ruler; ruler.setRange(-10,10); ruler.setMinGap(10); ruler.setWidth(100); CPPUNIT_ASSERT_EQUAL(2.0, ruler.markGap()); CPPUNIT_ASSERT_EQUAL(-10.0, ruler.markOffset()); } void testOffsetAndGap_withZoomOut() { CLAM::RulerTicks ruler; ruler.setRange(0,100); ruler.setMinGap(3); ruler.setWidth(10); CPPUNIT_ASSERT_EQUAL(50., ruler.markGap()); CPPUNIT_ASSERT_EQUAL(0.0, ruler.markOffset()); } void testOffsetAndGap_withOffsetAndMarkNotOnOffset() { CLAM::RulerTicks ruler; ruler.setRange(4,104); ruler.setMinGap(10); ruler.setWidth(100); CPPUNIT_ASSERT_EQUAL(10., ruler.markGap()); CPPUNIT_ASSERT_EQUAL(10.0, ruler.markOffset()); } void testNTicks() { CLAM::RulerTicks ruler; ruler.setRange(4,104); ruler.setMinGap(10); ruler.setWidth(100); CPPUNIT_ASSERT_EQUAL(10u, ruler.nTicks()); } }; } clam-1.4.0/test/UnitTests/StandardTests/RangeViewTest.cxx0000644000000000000000000000544611132120764022113 0ustar rootroot#include #include namespace CLAMTest { class RangeViewTest; CPPUNIT_TEST_SUITE_REGISTRATION( RangeViewTest ); class RangeViewTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE (RangeViewTest); CPPUNIT_TEST (testZoom_OutAtTheMiddle); CPPUNIT_TEST (testZoom_InAtTheMiddle); CPPUNIT_TEST (testZoom_InAtTheBegining); CPPUNIT_TEST (testZoom_OutAtTheBegining); CPPUNIT_TEST (testZoom_InAtTheEnd); CPPUNIT_TEST (testZoom_OutAtTheEnd); CPPUNIT_TEST (testKeepInRange_whenOverHighest); CPPUNIT_TEST (testKeepInRange_whenUnderLowest); CPPUNIT_TEST (testKeepInRange_whenDoesNotFit); CPPUNIT_TEST_SUITE_END(); private: void testZoom_OutAtTheMiddle() { double low = 4.2; double high = 10.2; CLAM::RangeView::zoom(low, high, 2, .5); CPPUNIT_ASSERT_DOUBLES_EQUAL(1.2, low, 1e-14); CPPUNIT_ASSERT_DOUBLES_EQUAL(13.2, high, 1e-14); } void testZoom_InAtTheMiddle() { double low = 4.2; double high = 10.2; CLAM::RangeView::zoom(low, high, .5, .5); CPPUNIT_ASSERT_DOUBLES_EQUAL(5.7, low, 1e-14); CPPUNIT_ASSERT_DOUBLES_EQUAL(8.7, high, 1e-14); } void testZoom_InAtTheBegining() { double low = 4.2; double high = 10.2; CLAM::RangeView::zoom(low, high, .5, 0.); CPPUNIT_ASSERT_DOUBLES_EQUAL(4.2, low, 1e-14); CPPUNIT_ASSERT_DOUBLES_EQUAL(7.2, high, 1e-14); } void testZoom_OutAtTheBegining() { double low = 4.2; double high = 10.2; CLAM::RangeView::zoom(low, high, 2., 0.); CPPUNIT_ASSERT_DOUBLES_EQUAL(4.2, low, 1e-14); CPPUNIT_ASSERT_DOUBLES_EQUAL(16.2, high, 1e-14); } void testZoom_InAtTheEnd() { double low = 4.2; double high = 10.2; CLAM::RangeView::zoom(low, high, .5, 1.); CPPUNIT_ASSERT_DOUBLES_EQUAL(7.2, low, 1e-14); CPPUNIT_ASSERT_DOUBLES_EQUAL(10.2, high, 1e-14); } void testZoom_OutAtTheEnd() { double low = 4.2; double high = 10.2; CLAM::RangeView::zoom(low, high, 2., 1.); CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.8, low, 1e-14); CPPUNIT_ASSERT_DOUBLES_EQUAL(10.2, high, 1e-14); } void testKeepInRange_whenOverHighest() { double low = 4.2; double high = 10.2; CLAM::RangeView::keepWithinInterval(low, high, 0, 10); CPPUNIT_ASSERT_DOUBLES_EQUAL(4.0, low, 1e-14); CPPUNIT_ASSERT_DOUBLES_EQUAL(10.0, high, 1e-14); } void testKeepInRange_whenUnderLowest() { double low = 4.2; double high = 10.2; CLAM::RangeView::keepWithinInterval(low, high, 5, 20); CPPUNIT_ASSERT_DOUBLES_EQUAL(5.0, low, 1e-14); CPPUNIT_ASSERT_DOUBLES_EQUAL(11.0, high, 1e-14); } void testKeepInRange_whenDoesNotFit() { double low = 4.2; double high = 10.2; CLAM::RangeView::keepWithinInterval(low, high, 0, 3); CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, low, 1e-14); CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, high, 1e-14); } }; } clam-1.4.0/test/UnitTests/StandardTests/StatsTest.cxx0000644000000000000000000001341610610720021021306 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "Stats.hxx" // CLAM namespace CLAMTest { class StatsTest; CPPUNIT_TEST_SUITE_REGISTRATION( StatsTest ); class StatsTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( StatsTest ); CPPUNIT_TEST( testCentroid ); CPPUNIT_TEST( testCentroid_withSingleDelta ); CPPUNIT_TEST( testCentroid_withSingleDeltaAtTheFirstBin ); CPPUNIT_TEST( testCentroid_withDeltasAtExtremes ); CPPUNIT_TEST( testCentroid_withEvenZeros ); CPPUNIT_TEST( testCentroid_withOddZeros ); CPPUNIT_TEST( testCentroid_withEvenConstant ); CPPUNIT_TEST( testCentroid_withOddConstant ); CPPUNIT_TEST( testMean_withNoElements ); CPPUNIT_TEST( testMoment1 ); CPPUNIT_TEST( testMoment2 ); CPPUNIT_TEST( testMoment3 ); CPPUNIT_TEST( testMoment4 ); CPPUNIT_TEST( testMoment5 ); CPPUNIT_TEST( testMoment6 ); CPPUNIT_TEST( testSlope_withPrimesUp ); CPPUNIT_TEST( testSlope_withPrimesDown ); CPPUNIT_TEST( testSlope_withConstant ); CPPUNIT_TEST( testSlope_withInvertedUp ); CPPUNIT_TEST_SUITE_END(); //@TODO: MRJ: Move to CppUnitHelper??? void assertDoublesEqual( double given, double expected, double eps ) { CPPUNIT_ASSERT( std::isnan(given) == std::isnan( expected ) ); CPPUNIT_ASSERT( std::isinf( given ) == std::isinf( expected ) ); CPPUNIT_ASSERT_DOUBLES_EQUAL( given, expected, eps); } public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: void fillPrimesUpInverted() { _array.AddElem(1/1.); _array.AddElem(1/2.); _array.AddElem(1/3.); _array.AddElem(1/5.); } void fillPrimesUp() { _array.AddElem(1.); _array.AddElem(2.); _array.AddElem(3.); _array.AddElem(5.); } void fillConstant() { _array.AddElem(3.); _array.AddElem(3.); _array.AddElem(3.); _array.AddElem(3.); } void fillPrimesDown() { _array.AddElem(5.); _array.AddElem(3.); _array.AddElem(2.); _array.AddElem(1.); } void fillCountUp() { _array.AddElem(1.); _array.AddElem(2.); _array.AddElem(3.); _array.AddElem(4.); } void fillCountDown() { _array.AddElem(4.); _array.AddElem(3.); _array.AddElem(2.); _array.AddElem(1.); } void fillLongLinearSerie() { for (unsigned i=0; i<1000; i++) { _array.AddElem(CLAM::TData(i)); } for (unsigned i=1000; i--; ) { _array.AddElem(CLAM::TData(i)); } } void fillZeros(unsigned int size) { for (unsigned i=0; i _array; private: void testCentroid() { fillPrimesUp(); CLAM::Stats stats(&_array); assertDoublesEqual( CLAM::TData(2.09091), stats.GetCentroid(), 0.000001); } void testCentroid_withSingleDelta() { fillZeros(50); _array[40]=CLAM::TData(1.0); CLAM::Stats stats(&_array); assertDoublesEqual( CLAM::TData(40.0), stats.GetCentroid(), 0.000001); } void testCentroid_withSingleDeltaAtTheFirstBin() { fillZeros(50); _array[0]=CLAM::TData(1.0); CLAM::Stats stats(&_array); assertDoublesEqual( CLAM::TData(0.0), stats.GetCentroid(), 0.000001); } void testCentroid_withEvenZeros() { fillZeros(50); CLAM::Stats stats(&_array); assertDoublesEqual( CLAM::TData(24.5), stats.GetCentroid(), 0.000001); } void testCentroid_withOddZeros() { fillZeros(51); CLAM::Stats stats(&_array); assertDoublesEqual( CLAM::TData(25.0), stats.GetCentroid(), 0.000001); } void testCentroid_withEvenConstant() { fillWith(50,2.0); CLAM::Stats stats(&_array); assertDoublesEqual( CLAM::TData(24.5), stats.GetCentroid(), 0.000001); } void testCentroid_withOddConstant() { fillWith(51,2.0); CLAM::Stats stats(&_array); assertDoublesEqual( CLAM::TData(25.0), stats.GetCentroid(), 0.000001); } void testCentroid_withDeltasAtExtremes() { fillZeros(50); _array[0]=CLAM::TData(1.0); _array[49]=CLAM::TData(1.0); CLAM::Stats stats(&_array); assertDoublesEqual( CLAM::TData(24.5), stats.GetCentroid(), 0.000001); } void testMean_withNoElements() { CLAM::Stats stats(&_array); CPPUNIT_ASSERT_EQUAL( CLAM::TData(0.0), stats.GetMean()); } void testMoment1() { fillPrimesUp(); CLAM::Stats stats(&_array); CPPUNIT_ASSERT_EQUAL( CLAM::TData(2.75), stats.GetMoment((CLAM::O<1>*)0)); } void testMoment2() { fillPrimesUp(); CLAM::Stats stats(&_array); CPPUNIT_ASSERT_EQUAL( CLAM::TData(9.75), stats.GetMoment((CLAM::O<2>*)0)); } void testMoment3() { fillPrimesUp(); CLAM::Stats stats(&_array); CPPUNIT_ASSERT_EQUAL( CLAM::TData(40.25), stats.GetMoment((CLAM::O<3>*)0)); } void testMoment4() { fillPrimesUp(); CLAM::Stats stats(&_array); CPPUNIT_ASSERT_EQUAL( CLAM::TData(180.75), stats.GetMoment((CLAM::O<4>*)0)); } void testMoment5() { fillPrimesUp(); CLAM::Stats stats(&_array); CPPUNIT_ASSERT_EQUAL( CLAM::TData(850.25), stats.GetMoment((CLAM::O<5>*)0)); } void testMoment6() { fillPrimesUp(); CLAM::Stats stats(&_array); CPPUNIT_ASSERT_EQUAL( CLAM::TData(4104.75), stats.GetMoment((CLAM::O<6>*)0)); } void testSlope_withPrimesUp() { fillPrimesUp(); CLAM::Stats stats(&_array); assertDoublesEqual( CLAM::TData(0.118182), stats.GetSlope(), .000001); } void testSlope_withPrimesDown() { fillPrimesDown(); CLAM::Stats stats(&_array); assertDoublesEqual( CLAM::TData(-0.118182), stats.GetSlope(), .000001); } void testSlope_withConstant() { fillConstant(); CLAM::Stats stats(&_array); CPPUNIT_ASSERT_EQUAL( CLAM::TData(0.), stats.GetSlope()); } void testSlope_withInvertedUp() { fillPrimesUpInverted(); CLAM::Stats stats(&_array); assertDoublesEqual( CLAM::TData(-0.126229), stats.GetSlope(), .000001); } }; } // namespace CLAMTes clam-1.4.0/test/UnitTests/ExamplesTests/0000755000000000000000000000000011344207072016650 5ustar rootrootclam-1.4.0/test/UnitTests/ExamplesTests/NetworkEditorTests/0000755000000000000000000000000011344231440022467 5ustar rootrootclam-1.4.0/test/UnitTests/ExamplesTests/NetworkEditorTests/TestNetworkEditorRunnerConsole.cxx0000644000000000000000000000204210014727704031374 0ustar rootroot #include #include #include #include #include "cppUnitHelper.hxx" #include "Assert.hxx" #include int main(int argc, char ** argv) { QApplication app( argc, argv ); // this flag allows clam asserts to behave throwing an exception instead // of doing breakpoint. Thus making auto-testing of asserts possible. // Notice: while debugging tests (if breakpoints are wanted back) you might need to // modify this flag before the point to be debugged. CLAM::ErrAssertionFailed::breakpointInCLAMAssertEnabled = false; CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry(); CppUnit::Test* theTest = registry.makeTest(); CLAMTest::Helper::printTestNames( theTest ); // We could just run() the suite. But using TestRunner we get // the exit code as well. CppUnit::TextUi::TestRunner runner; runner.addTest( theTest ); // caution: it deletes the suite on termination. return !runner.run(""); } clam-1.4.0/test/UnitTests/ExamplesTests/NetworkEditorTests/SignalsSlotsTest.cxx0000644000000000000000000000224410610720021026473 0ustar rootroot #include #include "BaseLoggable.hxx" // also includes #include #include "Signalv1.hxx" #include "Slotv1.hxx" class A { public: SigSlot::Signalv1< const std::string & > SignalSendB; SigSlot::Slotv1< const std::string & > SlotReceiveA; void ReceiveA( const std::string & ) { } A() { SlotReceiveA.Wrap( this, &A::ReceiveA ); } }; class B { public: SigSlot::Signalv1< const std::string & > SignalSendA; SigSlot::Slotv1< const std::string & > SlotReceiveB; void ReceiveB( const std::string & ) { } B() { SlotReceiveB.Wrap( this, &B::ReceiveB ); } void Attach( A & a ) { SignalSendA.Connect( a.SlotReceiveA ); a.SignalSendB.Connect( SlotReceiveB ); } }; namespace CLAMTest { class SignalsSlotsTest; CPPUNIT_TEST_SUITE_REGISTRATION( SignalsSlotsTest ); class SignalsSlotsTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( SignalsSlotsTest ); CPPUNIT_TEST( testDoubleConnection ); CPPUNIT_TEST_SUITE_END(); void testDoubleConnection() { A * a = new A; B * b = new B; b->Attach( *a ); delete b; delete a; // CPPUNIT_FAIL("oho"); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/TestRunnerConsole.cxx0000644000000000000000000000173110442000724020222 0ustar rootroot#include #include #include #include #include "cppUnitHelper.hxx" #include "Assert.hxx" // CLAM int main(void){ // this flag allows clam asserts to behave throwing an exception instead // of doing breakpoint. Thus making auto-testing of asserts possible. // Notice: while debugging tests (if breakpoints are wanted back) you might need to // modify this flag before the point to be debugged. CLAM::ErrAssertionFailed::breakpointInCLAMAssertEnabled = false; CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry(); CppUnit::Test* theTest = registry.makeTest(); CLAMTest::Helper::printTestNames( theTest ); // We could just run() the suite. But using TestRunner we get // the exit code as well. CppUnit::TextUi::TestRunner runner; runner.addTest( theTest ); // caution: it deletes the suite on termination. return !runner.run(""); } clam-1.4.0/test/UnitTests/SkeletonForNewTests.cxx.txt0000644000000000000000000000140707676355317021366 0ustar rootroot#include #include "cppUnitHelper.hxx" // necessary for the custom assert namespace CLAMTest { class SomeClassTest; CPPUNIT_TEST_SUITE_REGISTRATION( SomeClassTest ); class SomeClassTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( SomeClassTest ); CPPUNIT_TEST( testSomeMethod_WhenSomeConditionsMeet ); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: void testSomeMethod_WhenSomeConditionsMeet() { // Setup // Exercise // Verification CPPUNIT_ASSERT_EQUAL( *** Expected Result ***, *** Given Result *** ); // Tear down } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/ControlsTests/0000755000000000000000000000000011344231437016677 5ustar rootrootclam-1.4.0/test/UnitTests/ControlsTests/TypedControlsTests.cxx0000644000000000000000000003373211324127520023262 0ustar rootroot#include #include #include #include #include #include "BaseLoggable.hxx" #include namespace CLAMTest { class TypedControlsTest; CPPUNIT_TEST_SUITE_REGISTRATION( TypedControlsTest ); class TypedControlsTest : public CppUnit::TestFixture, public BaseLoggable, public CLAM::Processing { CPPUNIT_TEST_SUITE( TypedControlsTest ); // testing InControl and OutControl CPPUNIT_TEST( testInControl_DoControl_ChangesInternalState ); CPPUNIT_TEST( testAddLinkAndSendControl_ChangesInControlInternalState ); // tests for IsConnected / IsConnectedTo CPPUNIT_TEST( testIsConnected_WithOutControl_AfterConnection ); CPPUNIT_TEST( testIsConnected_WithOutControl_WithoutConnection ); CPPUNIT_TEST( testIsConnectedTo_WithOutControl_WhenControlsAreConnected ); CPPUNIT_TEST( testIsConnectedTo_WithOutControl_WhenControlsAreNotConnected ); CPPUNIT_TEST( testInControlIsConnected_byDefault ); CPPUNIT_TEST( testInControlIsConnected_whenConnected ); CPPUNIT_TEST( testInControlIsConnected_whenDisconnected ); // Destructor disconnections CPPUNIT_TEST( testInControlDestructor_disconnectsOutControl ); CPPUNIT_TEST( testOutControlDestructor_disconnectsInControl ); // 1 Out - Many Ins Test CPPUNIT_TEST( testOneOutControlManyInControls_DoControl_ChangesInternalState ); // Template Link Tests CPPUNIT_TEST( testIsLinkable_withDifferentControls ); CPPUNIT_TEST( testIsLinkable_withSameControls ); CPPUNIT_TEST( testAddLink_withSameControls ); CPPUNIT_TEST( testAddLink_withDifferentControls ); CPPUNIT_TEST( testIsConnected_WithOutControl_AfterConnection_withFloat ); CPPUNIT_TEST( testIsConnected_WithOutControl_WithNoConnection_withFloat ); CPPUNIT_TEST( testIsConnectedTo_WithOutControl_WhenControlsAreConnected_withFloat ); CPPUNIT_TEST( testIsConnectedTo_WithOutControl_WhenControlsAreNotConnected_withFloat ); // testing InControl Callbacks CPPUNIT_TEST( testInControlWithCallback_DoControl_ChangesInternalState ); CPPUNIT_TEST( testLinkAndSendWithInControl_CallbackMethodGetsCalled ); CPPUNIT_TEST( testLinkAndSendWithInControl_CopyCallbackMethodGetsCalled ); CPPUNIT_TEST( testControlHandlerId_WritesToLog ); CPPUNIT_TEST( testLinkAndSendWithInControl_CallbackWithIdMethodGetsCalled ); CPPUNIT_TEST( testLinkAndSendWithInControl_CopyCallbackWithIdMethodGetsCalled ); // *ControlRegistry Tests CPPUNIT_TEST( testInControlRegistry_ProcessingInterface_Register_ChangesInternalState ); CPPUNIT_TEST( testOutControlRegistry_ProcessingInterface_Register_ChangesInternalState ); CPPUNIT_TEST( testInControlRegistry_Has_loadingControlWithSameName ); CPPUNIT_TEST( testOutControlRegistry_Has_loadingControlWithSameName ); CPPUNIT_TEST( testInControlRegistry_Has_withNoControls ); CPPUNIT_TEST( testOutControlRegistry_Has_withNoControls ); // Testing bounds CPPUNIT_TEST( testInControl_doesntHaveBoundsBydefault ); CPPUNIT_TEST( testInControl_defaultBounds ); CPPUNIT_TEST( testInControl_settingBounds ); CPPUNIT_TEST( testInControl_boundedDefaultValue ); CPPUNIT_TEST( testInControl_isBoundedWhenTrue ); // Testing default value CPPUNIT_TEST( testInControl_setDefaultprevailstoBounds ); CPPUNIT_TEST_SUITE_END(); // Testing pattern: Self Shunt // Processing interface: const char* GetClassName() const { return "for testing"; } bool Do() { return false; } public: void tearDown() { ClearLog(); } // testing InControl and OutControl void testInControl_DoControl_ChangesInternalState() { CLAM::InControl in("IntInControl"); in.DoControl(1); CPPUNIT_ASSERT_EQUAL( 1, in.GetLastValue() ); } void testAddLinkAndSendControl_ChangesInControlInternalState() { CLAM::InControl in("IntInControl"); CLAM::OutControl out("IntOutControl"); out.AddLink(in); out.SendControl(1); CPPUNIT_ASSERT_EQUAL( 1 , in.GetLastValue() ); } // tests for IsConnected / IsConnectedTo void testIsConnected_WithOutControl_AfterConnection() { CLAM::InControl in("IntInControl"); CLAM::OutControl out("IntOutControl"); out.AddLink(in); CPPUNIT_ASSERT_EQUAL( true, out.IsConnected() ); } void testIsConnected_WithOutControl_WithoutConnection() { CLAM::OutControl out("IntOutControl"); CPPUNIT_ASSERT_EQUAL( false, out.IsConnected() ); } void testIsConnectedTo_WithOutControl_WhenControlsAreConnected() { CLAM::InControl in("IntInControl"); CLAM::OutControl out("IntOutControl"); out.AddLink(in); CPPUNIT_ASSERT_EQUAL( true, out.IsConnectedTo(in) ); } void testIsConnectedTo_WithOutControl_WhenControlsAreNotConnected() { CLAM::InControl in("IntInControl"); CLAM::OutControl out("IntOutControl"); CPPUNIT_ASSERT_EQUAL( false, out.IsConnectedTo(in) ); } void testInControlIsConnected_byDefault() { CLAM::InControl in("IntInControl"); CPPUNIT_ASSERT_EQUAL(false, in.IsConnected()); } void testInControlIsConnected_whenConnected() { CLAM::InControl in("IntInControl"); CLAM::OutControl out("IntOutControl"); out.AddLink(in); CPPUNIT_ASSERT_EQUAL(true, in.IsConnected()); } void testInControlIsConnected_whenDisconnected() { CLAM::InControl in("IntInControl"); CLAM::OutControl out("IntOutControl"); out.AddLink(in); out.RemoveLink(in); CPPUNIT_ASSERT_EQUAL(false, in.IsConnected()); } // Destructor disconnections void testInControlDestructor_disconnectsOutControl() { CLAM::OutControl out("IntOutControl"); { CLAM::InControl in("IntInControl"); out.AddLink(in); } CPPUNIT_ASSERT_EQUAL(false, out.IsConnected()); } void testOutControlDestructor_disconnectsInControl() { CLAM::InControl in("IntInControl"); { CLAM::OutControl out("IntOutControl"); out.AddLink(in); } CPPUNIT_ASSERT_EQUAL(false, in.IsConnected()); } // 1 Out - Many Ins Test void testOneOutControlManyInControls_DoControl_ChangesInternalState() { CLAM::OutControl out("IntOutControl"); CLAM::InControl in1("IntInControl 1"); CLAM::InControl in2("IntInControl 2"); out.AddLink(in1); out.AddLink(in2); out.SendControl(1); CPPUNIT_ASSERT_EQUAL( 1 , in1.GetLastValue() ); CPPUNIT_ASSERT_EQUAL( 1 , in2.GetLastValue() ); } // Template Link Tests void testIsLinkable_withDifferentControls() { CLAM::InControl concreteIn("Concrete In"); CLAM::OutControl concreteOut("Concrete Out"); CLAM::InControlBase & in = concreteIn; CLAM::OutControlBase & out = concreteOut; CPPUNIT_ASSERT_EQUAL(false, out.IsLinkable(in)); } void testIsLinkable_withSameControls() { CLAM::InControl concreteIn("Concrete In"); CLAM::OutControl concreteOut("Concrete Out"); CLAM::InControlBase & in = concreteIn; CLAM::OutControlBase & out = concreteOut; CPPUNIT_ASSERT_EQUAL(true, out.IsLinkable(in)); } void testAddLink_withDifferentControls() { CLAM::InControl concreteIn("Concrete In"); CLAM::OutControl concreteOut("Concrete Out"); CLAM::InControlBase & in = concreteIn; CLAM::OutControlBase & out = concreteOut; try { out.AddLink(in); CPPUNIT_FAIL("assertion failed expected, but nothing happened"); } catch(CLAM::ErrAssertionFailed& ) {} } void testAddLink_withSameControls() { CLAM::InControl concreteIn("Concrete In"); CLAM::OutControl concreteOut("Concrete Out"); CLAM::InControlBase & in = concreteIn; CLAM::OutControlBase & out = concreteOut; out.AddLink(in); CPPUNIT_ASSERT_EQUAL(true, concreteOut.IsConnectedTo(concreteIn)); } void testIsConnected_WithOutControl_AfterConnection_withFloat() { CLAM::InControl concreteIn("Concrete In"); CLAM::OutControl concreteOut("Concrete Out"); CLAM::InControlBase & in = concreteIn; CLAM::OutControlBase & out = concreteOut; out.AddLink(in); CPPUNIT_ASSERT_EQUAL(true, out.IsConnected()); } void testIsConnected_WithOutControl_WithNoConnection_withFloat() { CLAM::OutControl concreteOut("Concrete Out"); CLAM::OutControlBase & out = concreteOut; CPPUNIT_ASSERT_EQUAL(false, out.IsConnected()); } void testIsConnectedTo_WithOutControl_WhenControlsAreConnected_withFloat() { CLAM::InControl concreteIn("Concrete In"); CLAM::OutControl concreteOut("Concrete Out"); CLAM::InControlBase & in = concreteIn; CLAM::OutControlBase & out = concreteOut; out.AddLink(in); CPPUNIT_ASSERT_EQUAL(true, out.IsConnectedTo(in)); } void testIsConnectedTo_WithOutControl_WhenControlsAreNotConnected_withFloat() { CLAM::InControl concreteIn("Concrete In"); CLAM::OutControl concreteOut("Concrete Out"); CLAM::InControlBase & in = concreteIn; CLAM::OutControlBase & out = concreteOut; CPPUNIT_ASSERT_EQUAL(false, out.IsConnectedTo(in)); } // testing CascadingInControl void testInControlWithCallback_DoControl_ChangesInternalState() { CLAM::InControl in("in", this, &TypedControlsTest::ControlHandler); in.DoControl(1); CPPUNIT_ASSERT_EQUAL( 1, in.GetLastValue() ); } // helper method used for handling incoming control void ControlHandler(const int & val) { ToLog() << "ControlHandler called with: " << val; } void ControlCopyHandler(int val) { ToLog() << "ControlHandler called with: " << val; } void testLinkAndSendWithInControl_CallbackMethodGetsCalled() { CLAM::InControl in("in", this, &TypedControlsTest::ControlHandler); in.DoControl(1); CPPUNIT_ASSERT_EQUAL( std::string("ControlHandler called with: 1"), GetLog() ); } void testLinkAndSendWithInControl_CopyCallbackMethodGetsCalled() { CLAM::InControl in("in", this, &TypedControlsTest::ControlCopyHandler); in.DoControl(1); CPPUNIT_ASSERT_EQUAL( std::string("ControlHandler called with: 1"), GetLog() ); } // helper method for handling incoming control plus incontrol ID void ControlHandlerId(unsigned id, const int & val) { ToLog() << "ControlHandler called with id : " << id << " and value : " << val; } void ControlCopyHandlerId(unsigned id, int val) { ToLog() << "ControlHandler called with id : " << id << " and value : " << val; } void testControlHandlerId_WritesToLog() { ControlHandlerId(0, 1); CPPUNIT_ASSERT_EQUAL( std::string("ControlHandler called with id : 0 and value : 1"), GetLog() ); } void testLinkAndSendWithInControl_CallbackWithIdMethodGetsCalled() { const unsigned controlId=2; CLAM::InControl in( controlId, "in", this, &TypedControlsTest::ControlHandlerId ); in.DoControl( 1 ); CPPUNIT_ASSERT_EQUAL( GetLog(), std::string("ControlHandler called with id : 2 and value : 1") ); // note that controlId == 2 } void testLinkAndSendWithInControl_CopyCallbackWithIdMethodGetsCalled() { const unsigned controlId=2; CLAM::InControl in( controlId, "in", this, &TypedControlsTest::ControlCopyHandlerId ); in.DoControl( 1 ); CPPUNIT_ASSERT_EQUAL( GetLog(), std::string("ControlHandler called with id : 2 and value : 1") ); // note that controlId == 2 } // *ControlRegistry Tests // testing InControl and OutControl void testInControlRegistry_ProcessingInterface_Register_ChangesInternalState() { CLAM::InControl concreteIn("IntInControl"); CLAM::InControlBase & in = concreteIn; CLAM::InControlRegistry inRegistry; inRegistry.ProcessingInterface_Register(&in); CPPUNIT_ASSERT_EQUAL( &in, &inRegistry.Get("IntInControl") ); } void testOutControlRegistry_ProcessingInterface_Register_ChangesInternalState() { CLAM::OutControl concreteOut("IntOutControl"); CLAM::OutControlBase & out = concreteOut; CLAM::OutControlRegistry outRegistry; outRegistry.ProcessingInterface_Register(&out); CPPUNIT_ASSERT_EQUAL( &out, &outRegistry.Get("IntOutControl") ); } void testInControlRegistry_Has_loadingControlWithSameName() { CLAM::InControl concreteIn("IntInControl"); CLAM::InControlBase & in = concreteIn; CLAM::InControlRegistry inRegistry; inRegistry.ProcessingInterface_Register(&in); CPPUNIT_ASSERT_EQUAL( true, inRegistry.Has("IntInControl") ); } void testOutControlRegistry_Has_loadingControlWithSameName() { CLAM::OutControl concreteOut("IntOutControl"); CLAM::OutControlBase & out = concreteOut; CLAM::OutControlRegistry outRegistry; outRegistry.ProcessingInterface_Register(&out); CPPUNIT_ASSERT_EQUAL( true, outRegistry.Has("IntOutControl") ); } void testInControlRegistry_Has_withNoControls() { CLAM::InControlRegistry inRegistry; CPPUNIT_ASSERT_EQUAL( false, inRegistry.Has("IntInControl") ); } void testOutControlRegistry_Has_withNoControls() { CLAM::OutControlRegistry outRegistry; CPPUNIT_ASSERT_EQUAL( false, outRegistry.Has("IntOutControl") ); } void testInControl_doesntHaveBoundsBydefault() { CLAM::InControl concreteIn("InControl"); CLAM::InControlBase & inControl = concreteIn; CPPUNIT_ASSERT_EQUAL( false, inControl.IsBounded() ); } void testInControl_defaultBounds() { CLAM::InControl concreteIn("InControl"); CLAM::InControlBase & inControl = concreteIn; CPPUNIT_ASSERT_EQUAL( 0.0f, inControl.LowerBound() ); CPPUNIT_ASSERT_EQUAL( 1.0f, inControl.UpperBound() ); } void testInControl_settingBounds() { CLAM::InControl concreteIn("InControl"); CLAM::InControlBase & inControl = concreteIn; inControl.SetBounds(-1.f, 2.f); CPPUNIT_ASSERT_EQUAL( -1.f, inControl.LowerBound() ); CPPUNIT_ASSERT_EQUAL( 2.f, inControl.UpperBound() ); } void testInControl_boundedDefaultValue() { CLAM::InControl concreteIn("InControl"); CLAM::InControlBase & inControl = concreteIn; inControl.SetBounds(0.f, 10.f); CPPUNIT_ASSERT_EQUAL( 5.f, inControl.DefaultValue() ); } void testInControl_isBoundedWhenTrue() { CLAM::InControl concreteIn("InControl"); CLAM::InControlBase & inControl = concreteIn; inControl.SetBounds(0.f, 0.f); CPPUNIT_ASSERT_EQUAL( true, inControl.IsBounded() ); } void testInControl_setDefaultprevailstoBounds() { CLAM::InControl concreteIn("InControl"); CLAM::InControlBase & inControl = concreteIn; inControl.SetBounds(0.f, 10.f); inControl.SetDefaultValue(0.0f); CPPUNIT_ASSERT_EQUAL( 0.0f, inControl.DefaultValue() ); } }; } // namespace clam-1.4.0/test/UnitTests/ControlsTests/ControlsTest.cxx0000644000000000000000000003301011276620262022065 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "InControl.hxx" #include "OutControl.hxx" #include "OutControlPublisher.hxx" #include "InControlPublisher.hxx" #include "InControlArray.hxx" #include "BaseLoggable.hxx" #include "Processing.hxx" #include namespace CLAMTest { using CLAM::TControlData; class ControlsTest; CPPUNIT_TEST_SUITE_REGISTRATION( ControlsTest ); class ControlsTest : public CppUnit::TestFixture, public BaseLoggable, public CLAM::Processing { CPPUNIT_TEST_SUITE( ControlsTest ); // testing InControl and OutControl : CPPUNIT_TEST( testInControl_DoControl_ChangesInternalState ); CPPUNIT_TEST( testLinkAndSendControl_ChangesInControlInternalState ); CPPUNIT_TEST( testInControlTmpl_DoControl_ChangesInternalState ); CPPUNIT_TEST( testLinkAndSendWithInControlTmpl_CallbackMethodGetsCalled ); CPPUNIT_TEST( testControlHandlerId_WritesToLog ); CPPUNIT_TEST( testLinkAndSendWithInControlTmpl_CallbackWithIdMethodGetsCalled ); CPPUNIT_TEST( testInControl_GetName_ChangesInteralState ); CPPUNIT_TEST( testOutControl_GetName_ChangesInteralState ); // testing InControlArray : CPPUNIT_TEST( testInControlArray_Constructor_GeneratesCorrectName ); CPPUNIT_TEST( testInControlTmplArray_Constructor_GeneratesCorrectName ); CPPUNIT_TEST( testInControlTmplArray_ReceivesControl_HandlerReceivesControlAndId ); // tests for IsConnected / IsConnectedTo CPPUNIT_TEST( testIsConnected_WithOutControl_AfterConnection ); CPPUNIT_TEST( testIsConnected_WithOutControl_WithoutConnection ); CPPUNIT_TEST( testIsConnectedTo_WithOutControl_WhenControlsAreConnected ); CPPUNIT_TEST( testIsConnectedTo_WithOutControl_WhenControlsAreNotConnected ); CPPUNIT_TEST( testIsConnectedTo_WithInControl_WhenControlsAreConnected ); CPPUNIT_TEST( testIsConnectedTo_WithInControl_WhenControlsAreNotConnected ); // tests for Control Publishers //TODO CPPUNIT_TEST( testOutControlPublisher ); CPPUNIT_TEST( testOutControlPublisher_GetsRegisteredToAProcessing ); CPPUNIT_TEST( testOutControlPublisher_ConnectControlsFromPublisher ); CPPUNIT_TEST( testOutControlPublisher_SendControlWhenNothingPublished ); CPPUNIT_TEST( testInControlPublisher ); CPPUNIT_TEST( testInControlPublisher_GetsRegisteredToAProcessing ); CPPUNIT_TEST( testInControlPublisher_ConnectControlsFromPublisher ); CPPUNIT_TEST( testInControlPublisher_DoControlWhenNothingPublished ); // Backward reference CPPUNIT_TEST( testInControlIsConnected_byDefault ); CPPUNIT_TEST( testInControlIsConnected_whenConnected ); CPPUNIT_TEST( testInControlIsConnected_whenDisconnected ); // Destructor disconnections CPPUNIT_TEST( testInControlDestructor_disconnectsOutControl ); CPPUNIT_TEST( testOutControlDestructor_disconnectsInControl ); // Testing bounds CPPUNIT_TEST( testInControl_doesntHaveBoundsBydefault ); CPPUNIT_TEST( testInControl_defaultBounds ); CPPUNIT_TEST( testInControl_settingBounds ); CPPUNIT_TEST( testInControl_boundedDefaultValue ); CPPUNIT_TEST( testInControl_isBoundedWhenTrue ); // Testing default value CPPUNIT_TEST( testInControl_setDefaultprevailstoBounds ); CPPUNIT_TEST_SUITE_END(); // Testing pattern: Self Shunt // Processing interface: const char* GetClassName() const { return "for testing"; } bool Do() { return false; } public: void tearDown() { ClearLog(); } private: void testInControl_DoControl_ChangesInternalState() { CLAM::FloatInControl in("i'm an in control"); in.DoControl(1.f); CPPUNIT_ASSERT_EQUAL( 1.f, in.GetLastValue() ); } void testLinkAndSendControl_ChangesInControlInternalState() { CLAM::FloatInControl in("in"); CLAM::FloatOutControl out("out"); out.AddLink(in); out.SendControl(1.f); CPPUNIT_ASSERT_EQUAL( 1.f , in.GetLastValue() ); } // this method is used by the CLAM::InControlTmpl // here we are simulating that this class is the parent processing object public: void PublishInControl(CLAM::InControlBase* c) { ToLog() << "InControl published\n"; } private: void testInControlTmpl_DoControl_ChangesInternalState() { CLAM::FloatInControl in("I'm an in ctrl template", this);// calls this->PublishInControl in.DoControl(1.f); CPPUNIT_ASSERT_EQUAL( 1.f, in.GetLastValue() ); } // helper method used for handling incoming control void ControlHandler(CLAM::TControlData val) { ToLog() << "ControlHandler called with: " << val; } void testLinkAndSendWithInControlTmpl_CallbackMethodGetsCalled() { CLAM::FloatInControl in("in", this, &ControlsTest::ControlHandler); // calls this->PublishInControl ClearLog(); in.DoControl(1.f); CPPUNIT_ASSERT_EQUAL( std::string("ControlHandler called with: 1"), GetLog() ); } // helper method for handling incoming control plus incontrol ID void ControlHandlerId(unsigned id, CLAM::TControlData val) { ToLog() << "ControlHandler called with id : " << id << " and value : " << val; } void testControlHandlerId_WritesToLog() { ControlHandlerId(0, 1.0); CPPUNIT_ASSERT_EQUAL( std::string("ControlHandler called with id : 0 and value : 1"), GetLog() ); } void testLinkAndSendWithInControlTmpl_CallbackWithIdMethodGetsCalled() { const int controlId=2; CLAM::FloatInControl in( controlId, "in", this, &ControlsTest::ControlHandlerId ); // calls this->PublishInControl in.DoControl( 1.f ); CPPUNIT_ASSERT_EQUAL( GetLog(), std::string("ControlHandler called with id : 2 and value : 1") ); // note that controlId == 2 } void testInControl_GetName_ChangesInteralState() { CLAM::FloatInControl in("in name"); CPPUNIT_ASSERT_EQUAL(std::string("in name"), in.GetName() ); } void testOutControl_GetName_ChangesInteralState() { CLAM::FloatOutControl out("out name"); CPPUNIT_ASSERT_EQUAL(std::string("out name"), out.GetName() ); } void testInControlArray_Constructor_GeneratesCorrectName() { CLAM::InControlArray inControls (4, "name",this); CPPUNIT_ASSERT_EQUAL( std::string("name_0"), inControls[0].GetName() ); } void testInControlTmplArray_Constructor_GeneratesCorrectName() { CLAM::InControlArray inControls(4, "in", this, &ControlsTest::ControlHandlerId); CPPUNIT_ASSERT_EQUAL( std::string("in_3"), inControls[3].GetName() ); } void testInControlTmplArray_ReceivesControl_HandlerReceivesControlAndId() { CLAM::InControlArray ins( 2, /*num controls*/ "in", this, /*parent to publish (the fixture class is impersonating a processing)*/ &ControlsTest::ControlHandlerId ); // calls this->PublishInControl ins[1].DoControl( -1.0 ); CPPUNIT_ASSERT_EQUAL( std::string( "ControlHandler called with id : 1 and value : -1" ), GetLog() ); } void testIsConnected_WithOutControl_AfterConnection() { CLAM::FloatInControl in("in"); CLAM::FloatOutControl out("out"); out.AddLink(in); CPPUNIT_ASSERT_EQUAL( true, out.IsConnected() ); } void testIsConnected_WithOutControl_WithoutConnection() { CLAM::FloatOutControl out("out"); CPPUNIT_ASSERT_EQUAL( false, out.IsConnected() ); } void testIsConnectedTo_WithInControl_WhenControlsAreConnected() { CLAM::FloatInControl in("in"); CLAM::FloatOutControl out("out"); out.AddLink(in); CPPUNIT_ASSERT_EQUAL( true, in.IsConnectedTo(out) ); } void testIsConnectedTo_WithInControl_WhenControlsAreNotConnected() { CLAM::FloatInControl in("in"); CLAM::FloatOutControl out("out"); CPPUNIT_ASSERT_EQUAL( false, in.IsConnectedTo(out) ); } void testIsConnectedTo_WithOutControl_WhenControlsAreConnected() { CLAM::FloatInControl in("in"); CLAM::FloatOutControl out("out"); out.AddLink(in); CPPUNIT_ASSERT_EQUAL( true, out.IsConnectedTo(in) ); } void testIsConnectedTo_WithOutControl_WhenControlsAreNotConnected() { CLAM::FloatInControl in("in"); CLAM::FloatOutControl out("out"); CPPUNIT_ASSERT_EQUAL( false, out.IsConnectedTo(in) ); } void testOutControlPublisher() { CLAM::FloatInControl in("in"); CLAM::FloatOutControl out("out"); CLAM::OutControlPublisher outPublisher; outPublisher.PublishOutControl( out ); CLAM::FloatOutControl& publisherBaseRef = outPublisher; publisherBaseRef.AddLink(in); out.SendControl( 1.f ); CPPUNIT_ASSERT_EQUAL( 1.f, in.GetLastValue() ); } void testInControlPublisher() { CLAM::FloatInControl in("in"); CLAM::FloatOutControl out("out"); CLAM::InControlPublisher inPublisher; inPublisher.PublishInControl( in ); CLAM::FloatInControl& publisherBaseRef = inPublisher; out.AddLink( publisherBaseRef ); out.SendControl( 1.f ); CPPUNIT_ASSERT_EQUAL( 1.f, in.GetLastValue() ); } class DummyProcessing : public CLAM::Processing { public: CLAM::OutControlPublisher outControlPublisher; CLAM::InControlPublisher inControlPublisher; DummyProcessing() : outControlPublisher( "PublisherTestOut", this ) , inControlPublisher( "PublisherTestIn", this ) {} const char* GetClassName() const { return "dummy processing"; } bool Do() { return false; } const CLAM::ProcessingConfig& GetConfig() const { throw 0; } bool ConcreteConfigure( const CLAM::ProcessingConfig& ) { return false; } }; void testOutControlPublisher_GetsRegisteredToAProcessing() { DummyProcessing proc; CPPUNIT_ASSERT( &proc.outControlPublisher == &(proc.GetOutControl("PublisherTestOut")) ); } void testInControlPublisher_GetsRegisteredToAProcessing() { DummyProcessing proc; CPPUNIT_ASSERT( &proc.inControlPublisher == &(proc.GetInControl("PublisherTestIn")) ); } void testOutControlPublisher_ConnectControlsFromPublisher() { DummyProcessing proc; CLAM::FloatOutControl innerControlPublished("published"); // does the role of a "hidden" inner control CLAM::FloatInControl receiver("receiver"); proc.outControlPublisher.PublishOutControl( innerControlPublished ); proc.outControlPublisher.AddLink( receiver ); innerControlPublished.SendControl( 1.f ); CPPUNIT_ASSERT_EQUAL( 1.f, receiver.GetLastValue() ); } void testInControlPublisher_ConnectControlsFromPublisher() { DummyProcessing proc; CLAM::FloatInControl innerControlPublished("published"); // does the role of a "hidden" inner control CLAM::FloatOutControl sender("sender"); proc.inControlPublisher.PublishInControl( innerControlPublished ); sender.AddLink( proc.inControlPublisher ); sender.SendControl( 1.f ); CPPUNIT_ASSERT_EQUAL( 1.f, innerControlPublished.GetLastValue() ); } void testOutControlPublisher_SendControlWhenNothingPublished() { CLAM::OutControlPublisher publisher; CLAM::FloatInControl receiver("receiver"); publisher.AddLink(receiver); publisher.SendControl(1.f); CPPUNIT_ASSERT_EQUAL( 1.f, receiver.GetLastValue() ); } void testInControlPublisher_DoControlWhenNothingPublished() { CLAM::InControlPublisher publisher; publisher.DoControl(1.f); CPPUNIT_ASSERT_EQUAL( 1.f, publisher.GetLastValue() ); } void testInControlIsConnected_byDefault() { CLAM::FloatInControl in("Receiver"); CPPUNIT_ASSERT_EQUAL(false, in.IsConnected()); } void testInControlIsConnected_whenConnected() { CLAM::FloatInControl in("Receiver"); CLAM::FloatOutControl out("Sender"); out.AddLink(in); CPPUNIT_ASSERT_EQUAL(true, in.IsConnected()); } void testInControlIsConnected_whenDisconnected() { CLAM::FloatInControl in("Receiver"); CLAM::FloatOutControl out("Sender"); out.AddLink(in); out.RemoveLink(in); CPPUNIT_ASSERT_EQUAL(false, in.IsConnected()); } void testInControlDestructor_disconnectsOutControl() { CLAM::FloatOutControl out("Sender"); { CLAM::FloatInControl in("Receiver"); out.AddLink(in); } CPPUNIT_ASSERT_EQUAL(false, out.IsConnected()); } void testOutControlDestructor_disconnectsInControl() { CLAM::FloatInControl in("Receiver"); { CLAM::FloatOutControl out("Sender"); out.AddLink(in); } CPPUNIT_ASSERT_EQUAL(false, in.IsConnected()); } void testInControl_doesntHaveBoundsBydefault() { CLAM::FloatInControl inControl("inControl"); CPPUNIT_ASSERT_EQUAL( false, inControl.IsBounded() ); } void testInControl_defaultBounds() { CLAM::FloatInControl inControl("inControl"); CPPUNIT_ASSERT_EQUAL( 0.0f, inControl.LowerBound() ); CPPUNIT_ASSERT_EQUAL( 1.0f, inControl.UpperBound() ); } void testInControl_settingBounds() { CLAM::FloatInControl inControl("inControl"); inControl.SetBounds(-1.f, 2.f); CPPUNIT_ASSERT_EQUAL( -1.f, inControl.LowerBound() ); CPPUNIT_ASSERT_EQUAL( 2.f, inControl.UpperBound() ); } void testInControl_boundedDefaultValue() { CLAM::FloatInControl inControl("inControl"); inControl.SetBounds(0.f, 10.f); CPPUNIT_ASSERT_EQUAL( 5.f, inControl.DefaultValue() ); } void testInControl_isBoundedWhenTrue() { CLAM::FloatInControl inControl("inControl"); inControl.SetBounds(0.f, 0.f); CPPUNIT_ASSERT_EQUAL( true, inControl.IsBounded() ); } void testInControl_setDefaultprevailstoBounds() { CLAM::FloatInControl inControl("inControl"); inControl.SetBounds(0.f, 10.f); inControl.SetDefaultValue(0.0f); CPPUNIT_ASSERT_EQUAL( 0.0f, inControl.DefaultValue() ); } }; } // namespace clam-1.4.0/test/UnitTests/DescriptorsTests/0000755000000000000000000000000011344231436017374 5ustar rootrootclam-1.4.0/test/UnitTests/DescriptorsTests/ScopePoolTest.cxx0000644000000000000000000001701210610720021022650 0ustar rootroot/* * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "cppUnitHelper.hxx" #include "Pool.hxx" // CLAM #include "DataTypes.hxx" // CLAM namespace CLAMTest { class ScopePoolTest; CPPUNIT_TEST_SUITE_REGISTRATION( ScopePoolTest ); class ScopePoolTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ScopePoolTest ); CPPUNIT_TEST( testGetWritePool_ReturnsSameMemory ); CPPUNIT_TEST( testGetReadPool_ReturnsConstMemory ); CPPUNIT_TEST( testGetWritePool_withStrings ); CPPUNIT_TEST( testGetWritePool_withWrongType ); CPPUNIT_TEST( testGetReadPool_withWrongType ); CPPUNIT_TEST( testGetReadPool_withoutGetWritePoolFirst ); CPPUNIT_TEST( testConstruction_givesSizeZeroByDefault ); CPPUNIT_TEST( testSetSize_overAZeroSizePool ); CPPUNIT_TEST( testSetSize_overANonZeroSizePool ); CPPUNIT_TEST( testInsert ); CPPUNIT_TEST( testRemove ); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: void testGetWritePool_ReturnsSameMemory() { const unsigned poolSize=5; CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); CLAM::ScopePool pool(spec,poolSize); CLAM::TData * data = pool.GetWritePool("MyAttribute"); for (unsigned i = 0; i < poolSize; i++) data[i] = i*i; CLAM::TData * data2 = pool.GetWritePool("MyAttribute"); CPPUNIT_ASSERT_EQUAL(data,data2); } void testGetReadPool_ReturnsConstMemory() { const unsigned poolSize=5; CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); CLAM::ScopePool pool(spec,poolSize); CLAM::TData * data = pool.GetWritePool("MyAttribute"); for (unsigned i = 0; i < poolSize; i++) data[i] = i*i; const CLAM::ScopePool & pool2 = pool; const CLAM::TData * data2 = pool2.GetReadPool("MyAttribute"); CPPUNIT_ASSERT_EQUAL(const_cast(data),data2); } void testGetWritePool_withStrings() { const unsigned poolSize=5; CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); CLAM::ScopePool pool(spec,poolSize); std::string * data = pool.GetWritePool("MyAttribute"); for (unsigned i = 0; i < poolSize; i++) { std::ostringstream os; os << "Hola " << i*i; data[i] += os.str(); } const CLAM::ScopePool & pool2 = pool; const std::string * data2 = pool2.GetReadPool("MyAttribute"); const std::string expected = "Hola 16"; CPPUNIT_ASSERT_EQUAL(expected,data2[4]); } void testGetWritePool_withWrongType() { const unsigned poolSize=5; CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); CLAM::ScopePool pool(spec,poolSize); try { pool.GetWritePool("MyAttribute"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = std::string("Attribute 'TestScope:MyAttribute' has been used as type '") + typeid(int).name() + "' but it really was of type '" + typeid(std::string).name() + "'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testGetReadPool_withWrongType() { const unsigned poolSize=5; CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); CLAM::ScopePool pool(spec,poolSize); const CLAM::ScopePool & pool2 = pool; try { pool2.GetReadPool("MyAttribute"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = std::string("Attribute 'TestScope:MyAttribute' has been used as type '") + typeid(int).name() + "' but it really was of type '" + typeid(std::string).name() + "'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testGetReadPool_withoutGetWritePoolFirst() { CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); CLAM::ScopePool pool(spec,20); const CLAM::ScopePool & constPool = pool; try { constPool.GetReadPool("MyAttribute"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Getting data from a non instanciated attribute 'TestScope':'MyAttribute'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testConstruction_givesSizeZeroByDefault() { CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); CLAM::ScopePool pool(spec); CPPUNIT_ASSERT_EQUAL(0u,pool.GetSize()); } void testSetSize_overAZeroSizePool() { const unsigned poolSize=5; CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); CLAM::ScopePool pool(spec); pool.SetSize(poolSize); CLAM::TData * data = pool.GetWritePool("MyAttribute"); for (unsigned i = 0; i < poolSize; i++) data[i] = i*i; CLAM::TData * data2 = pool.GetWritePool("MyAttribute"); CPPUNIT_ASSERT_EQUAL(data,data2); } void testSetSize_overANonZeroSizePool() { const unsigned poolSize=5; CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); CLAM::ScopePool pool(spec,7); pool.SetSize(poolSize); CLAM::TData * data = pool.GetWritePool("MyAttribute"); for (unsigned i = 0; i < poolSize; i++) data[i] = i*i; CLAM::TData * data2 = pool.GetWritePool("MyAttribute"); CPPUNIT_ASSERT_EQUAL(data,data2); } void testInsert() { CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); CLAM::ScopePool pool(spec,3); CLAM::TData * data = pool.GetWritePool("MyAttribute"); for (unsigned i = 0; i < pool.GetSize(); i++) data[i] = 1000 + i*i; pool.Insert(2); unsigned expectedSize = 4; CLAM::TData expected[]={1000,1001,0,1004}; CPPUNIT_ASSERT_EQUAL(expectedSize,pool.GetSize()); const CLAM::TData * result = pool.GetReadPool("MyAttribute"); for (unsigned i=0; i("MyAttribute"); CLAM::ScopePool pool(spec,3); CLAM::TData * data = pool.GetWritePool("MyAttribute"); for (unsigned i = 0; i < pool.GetSize(); i++) data[i] = 1000 + i*i; pool.Remove(1); unsigned expectedSize = 2; CLAM::TData expected[]={1000,1004}; CPPUNIT_ASSERT_EQUAL(expectedSize,pool.GetSize()); const CLAM::TData * result = pool.GetReadPool("MyAttribute"); for (unsigned i=0; i #include "cppUnitHelper.hxx" #include "XMLTestHelper.hxx" #include "Pool.hxx" // CLAM #include "DataTypes.hxx" // CLAM #include "Spectrum.hxx" // CLAM #include "SpectrumConfig.hxx" // CLAM #include "Audio.hxx" // CLAM #include "SpectralAnalysis.hxx" // CLAM #include "XMLStorage.hxx" // CLAM #include "XMLAdapter.hxx" // CLAM #include namespace CLAMTest { class DescriptionXmlTest; CPPUNIT_TEST_SUITE_REGISTRATION( DescriptionXmlTest ); class DescriptionXmlTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( DescriptionXmlTest ); CPPUNIT_TEST(testDumpAttributePool_withSimpleData); CPPUNIT_TEST(testDumpAttributePool_withComponentData); CPPUNIT_TEST(testRestoreAttributePool_withSimpleData); CPPUNIT_TEST(testRestoreAttributePool_withComponentData); CPPUNIT_TEST(testRestoreAttributePool_withDifferentNameFails); CPPUNIT_TEST(testDumpScopePool_withNoAttributes); CPPUNIT_TEST(testDumpScopePool_withAttributesAndZeroSize); CPPUNIT_TEST(testDumpScopePool_withAttributes); CPPUNIT_TEST(testDumpScopePool_withIntegerAttributes); CPPUNIT_TEST(testDumpScopePool_withComponentAttributes); CPPUNIT_TEST(testDumpScopePool_withNonInstantiatedAttributes); CPPUNIT_TEST(testRestoreScopePool_withSingleAttribute); CPPUNIT_TEST(testRestoreScopePool_withSeveralAttributes); CPPUNIT_TEST(testRestoreScopePool_withBadScopeName); CPPUNIT_TEST(testDumpDescriptionDataPool_withAllKindsOfData); CPPUNIT_TEST(testRestoreDescriptionDataPool_withAllKindsOfData); CPPUNIT_TEST(testDumpSchema); CPPUNIT_TEST(testDumpMagnitudeAttributeSchema); CPPUNIT_TEST(testDumpStringAttributeSchema); CPPUNIT_TEST(testDumpComponentAttributeSchema); CPPUNIT_TEST(testRestoreSchema); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: std::ostringstream _targetStream; class DummyComponent : public CLAM::Component { public: void SetValue(const std::string & newValue) { _dummyMember=newValue; } const std::string & GetValue() const { return _dummyMember; } const char * GetClassName() const { return "DummyComponent"; } void StoreOn(CLAM::Storage & storage) const { CLAM::XMLAdapter adapter(_dummyMember,"DummyMember",false); storage.Store(adapter); } void LoadFrom(CLAM::Storage & storage) { CLAM::XMLAdapter adapter(_dummyMember,"DummyMember",false); storage.Load(adapter); } private: std::string _dummyMember; }; void assertXmlBodyEquals(const std::string & expectedXmlBody) { CPPUNIT_ASSERT_EQUAL(xmlHeader()+expectedXmlBody+xmlFooter(), _targetStream.str()); } void testDumpAttributePool_withSimpleData() { CLAM::Attribute attribute("MyAttribute"); CLAM::AttributePool pool; pool.SetDefinition(attribute); pool.Allocate(3); std::vector & data = * (std::vector*) pool.GetData(); for (unsigned int i = 0; i<3; i++) data[i]= -i; CLAM::XmlStorage::Dump(pool,"AttributePool",_targetStream,false); assertXmlBodyEquals( "" "0 -1 -2" "" ); pool.Deallocate(); } void testDumpAttributePool_withComponentData() { CLAM::Attribute attribute("MyAttribute"); CLAM::AttributePool pool; pool.SetDefinition(attribute); pool.Allocate(3); std::vector & data = * (std::vector*) pool.GetData(); data[0].SetValue("value0"); data[1].SetValue("value1"); data[2].SetValue("value2"); CLAM::XmlStorage::Dump(pool,"AttributePool",_targetStream,false); assertXmlBodyEquals( "" "" "" "" "" ); pool.Deallocate(); } void testDumpAttributePool_withNonDumpableData() { //TODO: } void testDumpAttributePool_withNoData() { //TODO: } void testRestoreAttributePool_withSimpleData() { std::istringstream input( "" "0 -1 -2" ""); CLAM::Attribute attribute("MyAttribute"); CLAM::AttributePool pool; pool.SetDefinition(attribute); pool.Allocate(3); CLAM::XmlStorage::Restore(pool, input); const std::vector & data = * (const std::vector*) pool.GetData(); for (unsigned int i = 0; i<3; i++) CPPUNIT_ASSERT_EQUAL((const int)-i, data[i]); pool.Deallocate(); } void testRestoreAttributePool_withComponentData() { std::istringstream input( "" "" "" "" ""); CLAM::Attribute attribute("MyAttribute"); CLAM::AttributePool pool; pool.SetDefinition(attribute); pool.Allocate(3); CLAM::XmlStorage::Restore(pool, input); const std::vector & data = * (std::vector*) pool.GetData(); const std::string value0("value0"), value1("value1"), value2("value2"); CPPUNIT_ASSERT_EQUAL(value0, data[0].GetValue()); CPPUNIT_ASSERT_EQUAL(value1, data[1].GetValue()); CPPUNIT_ASSERT_EQUAL(value2, data[2].GetValue()); pool.Deallocate(); } void testRestoreAttributePool_withDifferentNameFails() { std::istringstream input( "" "0 -1 -2" ""); CLAM::Attribute attribute("MyAttribute"); CLAM::AttributePool pool; pool.SetDefinition(attribute); pool.Allocate(3); try { CLAM::XmlStorage::Restore(pool, input); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "The schema expected an attribute named ':MyAttribute' but the XML file contained ':DifferentName'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } pool.Deallocate(); } void testRestoreAttributePool_withNonDumpableData() { //TODO: } void testRestoreAttributePool_withNoData() { //TODO: } void testRestoreScopePool_withSingleAttribute() { std::istringstream input( "" "" "value0 value1 value2" "" ""); CLAM::DescriptionScope scope("TestScope"); scope.Add("MyAttribute"); CLAM::ScopePool pool(scope); CLAM::XmlStorage::Restore(pool, input); CPPUNIT_ASSERT_EQUAL(3u, pool.GetSize()); const std::string * data = pool.GetWritePool("MyAttribute"); const std::string value0("value0"), value1("value1"), value2("value2"); CPPUNIT_ASSERT_EQUAL(value0, data[0]); CPPUNIT_ASSERT_EQUAL(value1, data[1]); CPPUNIT_ASSERT_EQUAL(value2, data[2]); } void testRestoreScopePool_withSeveralAttributes() { std::istringstream input( "" "" "value0 value1 value2" "" "" "0 -1 -2" "" ""); CLAM::DescriptionScope scope("TestScope"); scope.Add("MyAttribute"); scope.Add("MyOtherAttribute"); CLAM::ScopePool pool(scope); CLAM::XmlStorage::Restore(pool, input); CPPUNIT_ASSERT_EQUAL(3u, pool.GetSize()); { const std::string * data = pool.GetReadPool("MyAttribute"); const std::string value0("value0"), value1("value1"), value2("value2"); CPPUNIT_ASSERT_EQUAL(value0, data[0]); CPPUNIT_ASSERT_EQUAL(value1, data[1]); CPPUNIT_ASSERT_EQUAL(value2, data[2]); } { const int * data = pool.GetReadPool("MyOtherAttribute"); for (unsigned int i = 0; i<3; i++) CPPUNIT_ASSERT_EQUAL((const int)-i, data[i]); } } void testRestoreScopePool_withBadScopeName() { CLAM::DescriptionScope scope("TestScope"); scope.Add("MyAttribute"); CLAM::ScopePool pool(scope); std::istringstream input( "" "" "value0 value1 value2" "" ""); try { CLAM::XmlStorage::Restore(pool, input); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "The schema expected a scope named 'TestScope', but the XML contains the scope 'BadName' instead"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testDumpScopePool_withNoAttributes() { CLAM::DescriptionScope scope("TestScope"); CLAM::ScopePool pool(scope,20); CLAM::XmlStorage::Dump(pool,"ScopePool",_targetStream,false); assertXmlBodyEquals( "" ); } void testDumpScopePool_withAttributesAndZeroSize() { CLAM::DescriptionScope scope("TestScope"); scope.Add("MyAttribute"); CLAM::ScopePool pool(scope,0); std::string * values = pool.GetWritePool("MyAttribute"); CLAM::XmlStorage::Dump(pool,"ScopePool",_targetStream,false); assertXmlBodyEquals( "" "" "" "" ); } void testDumpScopePool_withAttributes() { CLAM::DescriptionScope scope("TestScope"); scope.Add("MyAttribute"); CLAM::ScopePool pool(scope,3); std::string * values = pool.GetWritePool("MyAttribute"); values[0]="value0"; values[1]="value1"; values[2]="value2"; CLAM::XmlStorage::Dump(pool,"ScopePool",_targetStream,false); assertXmlBodyEquals( "" "" "value0 value1 value2" "" "" ); } void testDumpScopePool_withIntegerAttributes() { CLAM::DescriptionScope scope("TestScope"); scope.Add("MyAttribute"); CLAM::ScopePool pool(scope,3); unsigned * values = pool.GetWritePool("MyAttribute"); values[0]=1; values[1]=2; values[2]=3; CLAM::XmlStorage::Dump(pool,"ScopePool",_targetStream,false); assertXmlBodyEquals( "" "" "1 2 3" "" "" ); } void testDumpScopePool_withComponentAttributes() { CLAM::DescriptionScope scope("TestScope"); scope.Add("MyAttribute"); CLAM::ScopePool pool(scope,3); DummyComponent * values = pool.GetWritePool("MyAttribute"); values[0].SetValue("value0"); values[1].SetValue("value1"); values[2].SetValue("value2"); CLAM::XmlStorage::Dump(pool,"ScopePool",_targetStream,false); assertXmlBodyEquals( "" "" "" "" "" "" "" ); } void testDumpScopePool_withNonInstantiatedAttributes() { CLAM::DescriptionScope scope("TestScope"); scope.Add("MyAttribute"); CLAM::ScopePool pool(scope,3); CLAM::XmlStorage::Dump(pool,"ScopePool",_targetStream,false); assertXmlBodyEquals( "" ); } void testDumpDescriptionDataPool_withAllKindsOfData() { CLAM::DescriptionScheme scheme; scheme.AddAttribute("TestScope1","DummyComponentAttribute"); scheme.AddAttribute("TestScope2","UnsignedAttribute"); scheme.AddAttribute("TestScope2","StringAttribute"); CLAM::DescriptionDataPool pool(scheme); pool.SetNumberOfContexts("TestScope1",3); pool.SetNumberOfContexts("TestScope2",4); { DummyComponent * values = pool.GetWritePool("TestScope1","DummyComponentAttribute"); values[0].SetValue("value0"); values[1].SetValue("value1"); values[2].SetValue("value2"); } { std::string * values = pool.GetWritePool("TestScope2","StringAttribute"); values[0]="value0"; values[1]="value1"; values[2]="value2"; values[3]="value3"; } { unsigned * values = pool.GetWritePool("TestScope2","UnsignedAttribute"); values[0]=0; values[1]=1; values[2]=2; values[3]=3; } CLAM::XmlStorage::Dump(pool,"DescriptionData",_targetStream,false); assertXmlBodyEquals( "" "" "" "" "" "" "" "" "" "" "0 1 2 3" "" "" "value0 value1 value2 value3" "" "" "" ); } void testRestoreDescriptionDataPool_withAllKindsOfData() { CLAM::DescriptionScheme scheme; scheme.AddAttribute("TestScope1","DummyComponentAttribute"); scheme.AddAttribute("TestScope2","UnsignedAttribute"); scheme.AddAttribute("TestScope2","StringAttribute"); CLAM::DescriptionDataPool pool(scheme); std::istringstream input( "" "" "" "" "" "" "" "" "" "" "0 1 2 3" "" "" "value0 value1 value2 value3" "" "" ""); CLAM::XmlStorage::Restore(pool, input); CPPUNIT_ASSERT_EQUAL(3u,pool.GetNumberOfContexts("TestScope1")); CPPUNIT_ASSERT_EQUAL(4u,pool.GetNumberOfContexts("TestScope2")); { DummyComponent * data = pool.GetWritePool("TestScope1","DummyComponentAttribute"); const std::string value0("value0"), value1("value1"), value2("value2"); CPPUNIT_ASSERT_EQUAL(value0, data[0].GetValue()); CPPUNIT_ASSERT_EQUAL(value1, data[1].GetValue()); CPPUNIT_ASSERT_EQUAL(value2, data[2].GetValue()); } { const std::string * data = pool.GetWritePool("TestScope2","StringAttribute"); const std::string value0("value0"), value1("value1"), value2("value2"), value3("value3"); CPPUNIT_ASSERT_EQUAL(value0, data[0]); CPPUNIT_ASSERT_EQUAL(value1, data[1]); CPPUNIT_ASSERT_EQUAL(value2, data[2]); CPPUNIT_ASSERT_EQUAL(value3, data[3]); } { const unsigned * data = pool.GetWritePool("TestScope2","UnsignedAttribute"); for (unsigned int i = 0; i<4; i++) CPPUNIT_ASSERT_EQUAL((const unsigned)i, data[i]); } } void testDumpMagnitudeAttributeSchema() { CLAM::Attribute attribute("MyScope", "MyAttribute"); CLAM::XmlStorage::Dump(attribute, "Attribute", _targetStream, false); assertXmlBodyEquals( "" ); } void testDumpStringAttributeSchema() { CLAM::Attribute attribute("MyScope", "MyAttribute"); CLAM::XmlStorage::Dump(attribute, "Attribute", _targetStream, false); assertXmlBodyEquals( "" ); } void testDumpComponentAttributeSchema() { CLAM::Attribute attribute("MyScope", "MyAttribute"); CLAM::XmlStorage::Dump(attribute, "Attribute", _targetStream, false); assertXmlBodyEquals( "" ); } void testDumpSchema() { CLAM::DescriptionScheme scheme; scheme.AddAttribute("MyScope","MyAttribute"); scheme.AddAttribute("YourScope","YourAttribute"); scheme.AddAttribute("YourScope","YourStringAttribute"); scheme.AddAttribute("YourScope","DummyComponentAttribute"); CLAM::XmlStorage::Dump(scheme, "DescriptionScheme", _targetStream, false); assertXmlBodyEquals( "" "" "" "" "" "" ); } void testRestoreSchema() { std::istringstream input( "" "" "" "" "" ); CLAM::DescriptionScheme scheme; CLAM::XmlStorage::Restore(scheme, input); CLAM::XmlStorage::Dump(scheme, "DescriptionScheme", _targetStream, false); assertXmlBodyEquals( "" "" "" "" "" ); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/DescriptorsTests/HookTest.cxx0000644000000000000000000001245410610720021021652 0ustar rootroot/* * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "cppUnitHelper.hxx" #include "Extractor.hxx" // CLAM #include "DataTypes.hxx" // CLAM namespace CLAMTest { class HookTest; CPPUNIT_TEST_SUITE_REGISTRATION( HookTest ); class HookTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( HookTest ); CPPUNIT_TEST(testInit_PointsToThePoolBegin); CPPUNIT_TEST(testNext_PointsToTheNextPoolData); CPPUNIT_TEST(testIsInsideScope_ReturnsTrueWhileInsideTheScope); CPPUNIT_TEST(testIsInsideScope_ReturnsFalseBeyondTheScope); CPPUNIT_TEST(testWriteInit_PointsToThePoolBegin); CPPUNIT_TEST(testWriteNext_PointsToTheNextPoolData); CPPUNIT_TEST(testWriteIsInsideScope_ReturnsTrueWhileInsideTheScope); CPPUNIT_TEST(testWriteIsInsideScope_ReturnsFalseBeyondTheScope); CPPUNIT_TEST(testTransformUsingHooks); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { mScheme.AddAttribute( "TestScope1","InputData"); mScheme.AddAttribute( "TestScope1","OutputData"); mPool = new CLAM::DescriptionDataPool(mScheme); mPool->SetNumberOfContexts("TestScope1",3); char * inputBuffer = mPool->GetWritePool("TestScope1","InputData"); for (unsigned i = 0; i<3; i++) inputBuffer[i]='a'+i; mInputBuffer = inputBuffer; } /// Common clean up, executed after each test method void tearDown() { delete mPool; } private: CLAM::DescriptionScheme mScheme; CLAM::DescriptionDataPool * mPool; const char * mInputBuffer; void testInit_PointsToThePoolBegin() { const char * expected = mInputBuffer; CLAM::ReadHook hook; hook.Bind("TestScope1","InputData"); hook.Init(*mPool); const char & result = hook.GetForReading(); CPPUNIT_ASSERT_EQUAL(expected, &result); } void testNext_PointsToTheNextPoolData() { const char * expected = mInputBuffer; CLAM::ReadHook hook; hook.Bind("TestScope1","InputData"); hook.Init(*mPool); hook.Next(); const char & result = hook.GetForReading(); CPPUNIT_ASSERT_EQUAL(expected+1, &result); } void testIsInsideScope_ReturnsTrueWhileInsideTheScope() { CLAM::ReadHook hook; hook.Bind("TestScope1","InputData"); hook.Init(*mPool); CPPUNIT_ASSERT(hook.IsInsideScope()); hook.Next(); CPPUNIT_ASSERT(hook.IsInsideScope()); hook.Next(); CPPUNIT_ASSERT(hook.IsInsideScope()); } void testIsInsideScope_ReturnsFalseBeyondTheScope() { CLAM::ReadHook hook; hook.Bind("TestScope1","InputData"); hook.Init(*mPool); // Advance until the end hook.Next(); hook.Next(); // Go Beyond hook.Next(); CPPUNIT_ASSERT(!hook.IsInsideScope()); } void testWriteInit_PointsToThePoolBegin() { CLAM::WriteHook hook; hook.Bind("TestScope1","OutputData"); hook.Init(*mPool); char & result = hook.GetForWriting(); char * expected = mPool->GetWritePool("TestScope1","OutputData"); CPPUNIT_ASSERT_EQUAL(expected, &result); } void testWriteNext_PointsToTheNextPoolData() { CLAM::WriteHook hook; hook.Bind("TestScope1","OutputData"); hook.Init(*mPool); hook.Next(); char & result = hook.GetForWriting(); char * expected = mPool->GetWritePool("TestScope1","OutputData") + 1; CPPUNIT_ASSERT_EQUAL(expected, &result); } void testWriteIsInsideScope_ReturnsTrueWhileInsideTheScope() { CLAM::WriteHook hook; hook.Bind("TestScope1","OutputData"); hook.Init(*mPool); CPPUNIT_ASSERT(hook.IsInsideScope()); hook.Next(); CPPUNIT_ASSERT(hook.IsInsideScope()); hook.Next(); CPPUNIT_ASSERT(hook.IsInsideScope()); } void testWriteIsInsideScope_ReturnsFalseBeyondTheScope() { CLAM::WriteHook hook; hook.Bind("TestScope1","OutputData"); hook.Init(*mPool); // Advance until the end hook.Next(); hook.Next(); // Go Beyond hook.Next(); CPPUNIT_ASSERT(!hook.IsInsideScope()); } void testTransformUsingHooks() { CLAM::WriteHook outputHook; CLAM::ReadHook inputHook; inputHook.Bind("TestScope1","InputData"); outputHook.Bind("TestScope1","OutputData"); inputHook.Init(*mPool); outputHook.Init(*mPool); for (; inputHook.IsInsideScope() && outputHook.IsInsideScope(); outputHook.Next(), inputHook.Next()) { char & output = outputHook.GetForWriting(); const char & input = inputHook.GetForReading(); output = input; } std::string expected(mPool->GetWritePool("TestScope1","InputData"),3); std::string result(mPool->GetWritePool("TestScope1","OutputData"),3); CPPUNIT_ASSERT_EQUAL(expected,result); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/DescriptorsTests/SpectralPeakDetectTest.cxx0000644000000000000000000000761710610720021024466 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "cppUnitHelper.hxx" #include "SpectralPeakArray.hxx" // CLAM #include "SpectralPeakDetect.hxx" // CLAM #include "Spectrum.hxx" // CLAM #include "FFT.hxx" // CLAM #include "SpecTypeFlags.hxx" // CLAM #include "AudioFile.hxx" // CLAM #include "MonoAudioFileReader.hxx" // CLAM #include "XMLStorage.hxx" // CLAM #include namespace CLAMTest { class SpectralPeakDetectTest; CPPUNIT_TEST_SUITE_REGISTRATION( SpectralPeakDetectTest ); class SpectralPeakDetectTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( SpectralPeakDetectTest ); CPPUNIT_TEST( test5kSin ); CPPUNIT_TEST_SUITE_END(); private: public: /// Common initialization, executed before each test method void setUp() { mPathToTestData = GetTestDataDirectory(""); } /// Common clean up, executed after each test method void tearDown() { } private: std::string mPathToTestData; CLAM::Spectrum ComputeSpectrum(const CLAM::Audio& audioData, int audioBlockSize=1024) { const CLAM::TSize spectrumSize = audioBlockSize/2 + 1; // Configure and create the spectrum CLAM::SpecTypeFlags specFlags; specFlags.bMagPhase = 1; CLAM::Spectrum mySpectrum; mySpectrum.SetType(specFlags); mySpectrum.SetSize(spectrumSize); // Configure the transform CLAM::FFTConfig FFTCfg; FFTCfg.SetAudioSize(audioBlockSize); // Compute the transform CLAM::FFT myFFT; myFFT.Configure(FFTCfg); myFFT.Start(); myFFT.Do(audioData, mySpectrum); myFFT.Stop(); // Return the result return mySpectrum; } CLAM::SpectralPeakArray ComputeSpectralPeaks(const CLAM::Spectrum& spectrum) { CLAM::SpectralPeakDetect peakDetect; CLAM::SpectralPeakDetectConfig peakDetectCfg; CLAM::SpectralPeakArray myPeakArray; CLAM::Spectrum dbSpectrum(spectrum); dbSpectrum.ToDB(); myPeakArray.SetScale(CLAM::EScale::eLog); peakDetect.Do(dbSpectrum,myPeakArray); myPeakArray.ToLinear(); return myPeakArray; } CLAM::Audio ReadAudio(const std::string & fileName, int audioBlockSize=1024) { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile(fileName); CLAM::MonoAudioFileReader reader; bool configOk = reader.Configure(cfg); CPPUNIT_ASSERT_MESSAGE( "configuration failed " + reader.GetConfigErrorMessage(), configOk); CLAM::Audio buf; buf.SetSize(audioBlockSize); reader.Start(); reader.Do( buf ); reader.Stop(); return buf; } CLAM::SpectralPeakArray helperGetData(const std::string & fileName) { std::string extension = fileName.substr(fileName.size()-4,fileName.size()); std::string fullPath = mPathToTestData+fileName; if (extension!=".xml") return ComputeSpectralPeaks(ComputeSpectrum(ReadAudio(fullPath, 512), 512)); CLAM::SpectralPeakArray peaks; CLAM::XMLStorage::Restore(peaks,fullPath); return peaks; } private: void test5kSin() { CLAM::SpectralPeakArray peaks; peaks = helperGetData("sin5000.wav"); CLAM::XMLStorage::Dump(peaks, "Peaks", "sin5000-Peaks.xml"); CPPUNIT_ASSERT( peaks.GetFreqBuffer()[0] > 4995); CPPUNIT_ASSERT( peaks.GetFreqBuffer()[0] < 5001); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/DescriptorsTests/ProofOfConceptTest.cxx0000644000000000000000000002310510610720021023633 0ustar rootroot/* * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "cppUnitHelper.hxx" #include "Extractor.hxx" // CLAM #include "Pool.hxx" // CLAM #include "DataTypes.hxx" // CLAM #include "Spectrum.hxx" // CLAM #include "SpectrumConfig.hxx" // CLAM #include "Audio.hxx" // CLAM #include "SpectralAnalysis.hxx" // CLAM #include "XMLStorage.hxx" // CLAM #include #include namespace CLAMTest { class ProofOfConceptTest; CPPUNIT_TEST_SUITE_REGISTRATION( ProofOfConceptTest ); class ProofOfConceptTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ProofOfConceptTest ); CPPUNIT_TEST(testUsingThePoolDirectly); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: void assertBackToBackMatches(const CLAM::Component & result, const std::string & referenceFilename) { std::ifstream referenceFile( (GetTestDataDirectory("DescriptionPool/") + referenceFilename).c_str() ); std::string reference( (std::istreambuf_iterator(referenceFile)), std::istreambuf_iterator() ); std::stringstream dumpedResult; CLAM::XmlStorage::Dump(result,"DescriptionData",dumpedResult); if (reference!=dumpedResult.str()) CLAM::XmlStorage::Dump(result,"DescriptionData",referenceFilename+".failed.xml"); CPPUNIT_ASSERT_EQUAL(reference,dumpedResult.str()); } void testUsingThePoolDirectly() { typedef unsigned SamplePosition; CLAM::DescriptionScheme scheme; scheme.AddAttribute ("AudioSample","Level"); scheme.AddAttribute ("Frame","Center"); scheme.AddAttribute ("Frame","Energy"); scheme.AddAttribute ("Frame","RMS"); scheme.AddAttribute ("Frame","SpectralDistribution"); // scheme.AddAttribute ("Song","EnergyCentroid"); CLAM::DescriptionDataPool pool(scheme); const unsigned audioSize = 1025; const unsigned frameSize = 256; // AudioSample pool.SetNumberOfContexts("AudioSample",audioSize); // AudioSample::Level { CLAM::TData * audio = pool.GetWritePool("AudioSample","Level"); for (unsigned i=0; i("Frame","Center"); for (unsigned i=0; i("Frame","Energy"); const SamplePosition * centers = pool.GetReadPool("Frame","Center"); const CLAM::TData * samples = pool.GetReadPool("AudioSample","Level"); for (unsigned i=0; i("Frame","RMS"); const CLAM::TData * energy = pool.GetReadPool("Frame","Energy"); for (unsigned i=0; i("Frame","SpectralDistribution"); const SamplePosition * centers = pool.GetReadPool("Frame","Center"); const CLAM::TData * samples = pool.GetReadPool("AudioSample","Level"); CLAM::SpecTypeFlags sflags; sflags.bMagPhase = true; sflags.bComplex = true; CLAM::SpectrumConfig specconf; specconf.SetType( sflags ); specconf.SetSpectralRange( 44100 / 2 ); specconf.SetSize( 257 ); CLAM::SpectralAnalysisConfig config; config.SetWindowSize(257); CLAM::SpectralAnalysis spectralAnalysis; spectralAnalysis.Start(); for (unsigned i=0; i(audio.GetBuffer()); audioBuffer.SetPtr(const_cast(samples+centers[i]),frameSize); spectrum.Configure(specconf); spectralAnalysis.Do(audio, spectrum); } spectralAnalysis.Stop(); } assertBackToBackMatches(pool,"SpectralAnalysis.xml"); } #ifdef NEVERDEFINED void testSubGoal() { CLAM::DescriptionScheme scheme; scheme.AddScope("Frame"); scheme.AddSignalScope("AudioSample"); scheme.AddAttribute ("AudioSample","Level"); scheme.AddAttribute("Frame","Center"); scheme.AddAttribute ("Frame","SpectralDistribution"); CLAM::Scoper * loader = CLAM::Extractor::Create("SoundLoader"); loader.BindOutputHook("AudioSample","Level"); CLAM::Scoper * frametizer = CLAM::Extractor::Create("Frametizer"); frametizer.BindOutputHook("Output","Frame"); frametizer.BindOutputHook("Center",""); frametizer.BindInputHook("Output") CLAM::Extractor * fft = CLAM::Extractor::Create("SpectralAnalysis"); scheme.AddExtractor(fft); fft.BindOutputHook("Output","Frame","SpectralDistribution"); fft.BindInputHook("Input", CurrentContext().Attribute("Center").Indirect("AudioSample").Range("WindowSize") .Attribute("Level").RelativeRange(-framesize/2,+framesize/2) ); scheme.AddExtractor(loader); scheme.AddExtractor(frametizer); scheme.SetParameter("FrameSize",256); CLAM::DescriptionDataPool pool(scheme); pool.ExtractFrom("mysong.mp3"); CLAM::XmlStorage::Dump(pool,"Description.xml","SimacDescription"); } /* ----------- DescriptionScheme.xml ... .... ... */ void testGoal() { CLAM::DescriptionScheme scheme("DescriptionScheme.xml"); scheme.AddPlugin("DescriptionSchemeExtension.xml"); scheme.SetParameter("FrameSize",256); CLAM::DescriptionDataPool pool(scheme); pool.ExtractFrom("mysong.mp3"); CLAM::XmlStorage::Dump(pool,"Description.xml","SimacDescription"); } /* 0.0 0.0 .342161 .... " 0 256 512 768 1024 1280 1536 1792 0 0.7256 0.4512 0.8768 .... 0 0.7256 0.4512 0.8768 .... 0 0.7256 0.4512 0.8768 .... .... 0.0 0.0 .342161 ....
0 256 512 768 1024 1280 1536 1792
0 0.7256 0.4512 0.8768 .... 0 0.7256 0.4512 0.8768 .... 0 0.7256 0.4512 0.8768 .... ....
*/ #endif }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/DescriptorsTests/CharCopierExtractor.hxx0000644000000000000000000000476710610720021024042 0ustar rootroot/* * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifndef _CharCopierExtractor_hxx_ #define _CharCopierExtractor_hxx_ #include "Extractor.hxx" // CLAM namespace CLAMTest { class CharCopierExtractor { public: CLAM::ReadHook & GetInHook() { return _inputHook; } CLAM::WriteHook & GetOutHook() { return _outputHook; } void Extract() { const char & input = _inputHook.GetForReading(); char & output = _outputHook.GetForWriting(); output = input; } bool IsInsideScope() { return _inputHook.IsInsideScope() && _outputHook.IsInsideScope(); } void Next() { _inputHook.Next(); _outputHook.Next(); } void Init(CLAM::DescriptionDataPool & pool) { _inputHook.Init(pool); _outputHook.Init(pool); } private: CLAM::ReadHook _inputHook; CLAM::WriteHook _outputHook; }; class CharJoinExtractor { public: void SetHooks(CLAM::ReadRangedHook & inputHook, CLAM::WriteHook & outputHook) { } CLAM::ReadRangedHook & GetInHook() { return _inputHook; } CLAM::WriteHook & GetOutHook() { return _outputHook; } void Extract() { const char * input; const char * inputEnd; _inputHook.GetRangeForReading(input, inputEnd); std::string & output = _outputHook.GetForWriting(); for (output = ""; input _inputHook; CLAM::WriteHook _outputHook; }; } // namespace CLAMTest #endif// _CharCopierExtractor_hxx_ clam-1.4.0/test/UnitTests/DescriptorsTests/ExtractorTest.cxx0000644000000000000000000001212610610720021022721 0ustar rootroot/* * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "cppUnitHelper.hxx" #include "Extractor.hxx" // CLAM #include "DataTypes.hxx" // CLAM #include "CharCopierExtractor.hxx" namespace CLAMTest { class ExtractorTest; CPPUNIT_TEST_SUITE_REGISTRATION( ExtractorTest ); class ExtractorTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ExtractorTest ); CPPUNIT_TEST(testInScopeBinding); CPPUNIT_TEST(testIndirectedBinding); CPPUNIT_TEST(testDoubleIndirectedBinding); CPPUNIT_TEST(testRangeIndirectBinding); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { mScheme.AddAttribute ( "Referenced","Input"); mScheme.AddAttribute ( "Referenced","Output"); mScheme.AddAttribute ( "Referenced","ReverseReference"); mScheme.AddAttribute ( "Referencer","BadReference"); mScheme.AddAttribute ( "Referencer","Reference"); mScheme.AddAttribute ( "Referencer","Output"); mScheme.AddAttribute( "Referencer","Concatenations"); mPool = new CLAM::DescriptionDataPool(mScheme); mPool->SetNumberOfContexts("Referenced",10); mPool->SetNumberOfContexts("Referencer",3); { char * inputBuffer = mPool->GetWritePool("Referenced","Input"); for (unsigned i = 0; i<10; i++) inputBuffer[i]='a'+i; } { unsigned * inputBuffer = mPool->GetWritePool("Referenced","ReverseReference"); for (unsigned i = 0; i<10; i++) inputBuffer[i]=9-i; } { unsigned * inputBuffer = mPool->GetWritePool("Referencer","Reference"); for (unsigned i = 0; i<3; i++) inputBuffer[i]=3*i; } { unsigned * inputBuffer = mPool->GetWritePool("Referencer","BadReference"); for (unsigned i = 0; i<3; i++) inputBuffer[i]=3*i; inputBuffer[0]=20; } } /// Common clean up, executed after each test method void tearDown() { delete mPool; } private: CLAM::DescriptionScheme mScheme; CLAM::DescriptionDataPool * mPool; void testInScopeBinding() { CharCopierExtractor extractor; CLAM::WriteHook outputHook; extractor.GetOutHook() .Bind("Referenced","Output"); extractor.GetInHook() .Bind("Referenced","Input"); for (extractor.Init(*mPool); extractor.IsInsideScope(); extractor.Next()) { extractor.Extract(); } std::string expected(mPool->GetWritePool("Referenced","Input"),3); std::string result(mPool->GetWritePool("Referenced","Output"),3); CPPUNIT_ASSERT_EQUAL(expected,result); } void testIndirectedBinding() { CharCopierExtractor extractor; CLAM::WriteHook outputHook; extractor.GetOutHook() .Bind("Referencer","Output"); extractor.GetInHook() .Bind("Referenced","Input") .Indirect("Referencer","Reference"); for (extractor.Init(*mPool); extractor.IsInsideScope(); extractor.Next()) { extractor.Extract(); } std::string expected("adg",3); std::string result(mPool->GetWritePool("Referencer","Output"),3); CPPUNIT_ASSERT_EQUAL(expected,result); } void testDoubleIndirectedBinding() { CharCopierExtractor extractor; CLAM::WriteHook outputHook; extractor.GetOutHook() .Bind("Referencer","Output"); extractor.GetInHook() .Bind("Referenced","Input") .Indirect("Referenced","ReverseReference") .Indirect("Referencer","Reference"); for (extractor.Init(*mPool); extractor.IsInsideScope(); extractor.Next()) { extractor.Extract(); } std::string expected("jgd",3); std::string result(mPool->GetWritePool("Referencer","Output"),3); CPPUNIT_ASSERT_EQUAL(expected,result); } void testRangeIndirectBinding() { CharJoinExtractor extractor; extractor.GetInHook() .Range(4) .Bind("Referenced","Input") .Indirect("Referencer","Reference"); extractor.GetOutHook() .Bind("Referencer","Concatenations"); for (extractor.Init(*mPool); extractor.IsInsideScope(); extractor.Next()) { extractor.Extract(); } std::string expected0("abcd",4); std::string expected1("defg",4); std::string expected2("ghij",4); std::string * results = mPool->GetWritePool("Referencer","Concatenations"); CPPUNIT_ASSERT_EQUAL(expected0,results[0]); CPPUNIT_ASSERT_EQUAL(expected1,results[1]); CPPUNIT_ASSERT_EQUAL(expected2,results[2]); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/DescriptorsTests/AttributePoolTest.cxx0000644000000000000000000000477311024063123023557 0ustar rootroot/* * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "cppUnitHelper.hxx" #include "AttributePool.hxx" // CLAM #include "DataTypes.hxx" // CLAM #include "Component.hxx" // CLAM namespace CLAMTest { class AttributePoolTest; CPPUNIT_TEST_SUITE_REGISTRATION( AttributePoolTest ); class AttributePoolTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( AttributePoolTest ); CPPUNIT_TEST(testGetData_returnsNullByDefault); CPPUNIT_TEST(testAllocatePool); CPPUNIT_TEST(testDeallocatePool); CPPUNIT_TEST(testDeallocatePool_whenNoPreviousAllocation); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: void testGetData_returnsNullByDefault() { CLAM::AttributePool pool; void * result = pool.GetData(); CPPUNIT_ASSERT_EQUAL((void*)0x0, result); } void testAllocatePool() { CLAM::Attribute definition("MyAttribute"); CLAM::AttributePool pool; pool.SetDefinition(definition); pool.Allocate(4); const void * data = pool.GetData(); CPPUNIT_ASSERT(data!=0); } void testDeallocatePool() { CLAM::Attribute definition("MyAttribute"); CLAM::AttributePool pool; pool.SetDefinition(definition); pool.Allocate(4); pool.Deallocate(); const void * data = pool.GetData(); CPPUNIT_ASSERT_EQUAL((const void*)0, data); } void testDeallocatePool_whenNoPreviousAllocation() { CLAM::Attribute definition("MyAttribute"); CLAM::AttributePool pool; pool.SetDefinition(definition); pool.Deallocate(); const void * data = pool.GetData(); CPPUNIT_ASSERT_EQUAL((const void*)0, data); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/DescriptorsTests/AudioDescriptorsTest.cxx0000644000000000000000000002217411016525555024255 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "cppUnitHelper.hxx" #include #include #include #include #include #include namespace CLAMTest { class AudioDescriptorsTest; CPPUNIT_TEST_SUITE_REGISTRATION( AudioDescriptorsTest ); class AudioDescriptorsTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( AudioDescriptorsTest ); CPPUNIT_TEST( testLogAttackTime ); CPPUNIT_TEST( testTemporalCentroid ); CPPUNIT_TEST( testZeroCrossingRate ); CPPUNIT_TEST( testEnergy ); // CPPUNIT_TEST( testDecrease ); CPPUNIT_TEST_SUITE_END(); private: public: /// Common initialization, executed before each test method void setUp() { mPathToTestData = GetTestDataDirectory() + "descriptorsData/"; mDescriptors = new CLAM::AudioDescriptors(); mDescriptors->RemoveAll(); } /// Common clean up, executed after each test method void tearDown() { delete mDescriptors; } private: CLAM::AudioDescriptors *mDescriptors; std::string mPathToTestData; CLAM::Audio ReadAudio(const std::string & fileName) { CLAM::MonoAudioFileReaderConfig infilecfg; infilecfg.SetSourceFile(fileName); CLAM::MonoAudioFileReader reader(infilecfg); CLAM::Audio buf; buf.SetSize(reader.GetHeader().GetSamples()); buf.SetSampleRate(reader.GetHeader().GetSampleRate()); reader.Start(); reader.Do(buf); reader.Stop(); return buf; } CLAM::Audio helperGetData(const std::string & fileName) { std::string extension = fileName.substr(fileName.size()-4,fileName.size()); std::string fullPath = mPathToTestData+fileName; if (extension!=".xml") return ReadAudio(fullPath); CLAM::Audio audio; CLAM::XMLStorage::Restore(audio,fullPath); return audio; } void assertDescriptorExtractionInsideTolerance(const std::map & expected, CLAM::TData tolerance, CLAM::TData & (CLAM::AudioDescriptors::*getter)() const ) { std::stringstream log; bool success = true; mDescriptors->UpdateData(); CLAM::Audio audio; std::map::const_iterator it; for (it = expected.begin(); it != expected.end(); it++) { audio = helperGetData((*it).first); mDescriptors->SetpAudio(&audio); mDescriptors->Compute(); if ( (std::isnan((mDescriptors->*getter)()) != std::isnan(it->second)) || (std::isinf((mDescriptors->*getter)()) != std::isinf(it->second)) || (mDescriptors->*getter)() > (*it).second + tolerance || (mDescriptors->*getter)() < (*it).second - tolerance ) { log << (*it).first << ": expected " << std::setprecision(15) << it->second << ", received " << std::setprecision(15) << (mDescriptors->*getter)() << ", difference " << std::setprecision(15) << (it->second - (mDescriptors->*getter)()) << std::endl; success = false; } } CPPUNIT_ASSERT_MESSAGE(std::string("Error margins surpassed:\n")+log.str() ,success); } private: void testLogAttackTime() { CLAM::TData tolerance = 0.0001; // Due to numerical inaccuracies std::map data; data["AltoSax-Iowa-ff-Db3B3-Region 012.wav"] = -1.380329; data["Balance000.600.wav"] = -1.691646; data["Balance000.992.wav"] = -1.687790; data["Balance001.988.wav"] = -1.501736; data["Balance010.910.wav"] = -1.672699; data["Cello_A2.wav"] = -1.114367; data["Cello_C2.wav"] = -0.166912; data["Disco_Rojo001.008.wav"] = -1.864842; data["Disco_Rojo002.327.wav"] = -1.605818; data["Geiger_Counter005.020.wav"] = -1.787106; data["SaxBritHorns12.wav"] = -1.697495; data["Time002.624.wav"] = -1.895476; data["bell_A3.wav"] = -1.703922; data["gamelan-gong.wav"] = -1.331838; data["gt_E4.wav"] = -2.216304; data["pno_Eb1.wav"] = -1.725360; data["silence.wav"] = -5.000000; data["vln_A3.wav"] = -0.572336; data["vln_D5.wav"] = -0.451927; data["whitenoise.wav"] = -1.897804; mDescriptors->AddLogAttackTime(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::AudioDescriptors::GetLogAttackTime); } void testTemporalCentroid() { CLAM::TData tolerance = 0.001; // Due to numerical inaccuracies std::map data; data["AltoSax-Iowa-ff-Db3B3-Region 012.wav"] = 1.10702383518219; data["Balance000.600.wav"] = 0.045051; data["Balance000.992.wav"] = 0.044318; data["Balance001.988.wav"] = 0.051773; data["Balance010.910.wav"] = 0.042667; data["Cello_A2.wav"] = 0.207102; data["Cello_C2.wav"] = 2.455419; data["Disco_Rojo001.008.wav"] = 0.049909; data["Disco_Rojo002.327.wav"] = 0.052137; data["Geiger_Counter005.020.wav"] = 0.053245; data["SaxBritHorns12.wav"] = 0.075114; data["Time002.624.wav"] = 0.050065; data["bell_A3.wav"] = 1.198206; data["gamelan-gong.wav"] = 1.803790; data["gt_E4.wav"] = 0.646689; data["pno_Eb1.wav"] = 2.3413622379303; data["silence.wav"] = 0.05; // Avoids NaN data["vln_A3.wav"] = 0.500487; data["vln_D5.wav"] = 0.456816; data["whitenoise.wav"] = 0.049801; mDescriptors->AddTemporalCentroid(); assertDescriptorExtractionInsideTolerance(data,tolerance, &CLAM::AudioDescriptors::GetTemporalCentroid); } void testZeroCrossingRate() { CLAM::TData tolerance = 0.006; // Due to numerical inaccuracies std::map data; data["AltoSax-Iowa-ff-Db3B3-Region 012.wav"] = 0.126168; data["Balance000.600.wav"] = 0.006349; data["Balance000.992.wav"] = 0.011791; data["Balance001.988.wav"] = 0.027891; data["Balance010.910.wav"] = 0.004989; data["Cello_A2.wav"] = 0.032868; data["Cello_C2.wav"] = 0.019433; data["Disco_Rojo001.008.wav"] = 0.123129; data["Disco_Rojo002.327.wav"] = 0.018594; data["Geiger_Counter005.020.wav"] = 0.029252; data["SaxBritHorns12.wav"] = 0.062320; data["Time002.624.wav"] = 0.287755; data["bell_A3.wav"] = 0.045547; data["gamelan-gong.wav"] = 0.006900; data["gt_E4.wav"] = 0.035136; data["pno_Eb1.wav"] = 0.011902; data["silence.wav"] = 0.000000; data["vln_A3.wav"] = 0.021366; data["vln_D5.wav"] = 0.060226; data["whitenoise.wav"] = 0.504535; mDescriptors->AddZeroCrossingRate(); assertDescriptorExtractionInsideTolerance(data,tolerance, &CLAM::AudioDescriptors::GetZeroCrossingRate); } void testEnergy() { CLAM::TData tolerance = 5.0; // Due to numerical inaccuracies std::map data; data["AltoSax-Iowa-ff-Db3B3-Region 012.wav"] = 1371.542406; data["Balance000.600.wav"] = 64.598414; data["Balance000.992.wav"] = 28.735406; data["Balance001.988.wav"] = 25.132553; data["Balance010.910.wav"] = 107.347657; data["Cello_A2.wav"] = 390.249943; data["Cello_C2.wav"] = 6398.441127; data["Disco_Rojo001.008.wav"] = 156.370021; data["Disco_Rojo002.327.wav"] = 160.895829; data["Geiger_Counter005.020.wav"] = 36.972497; data["SaxBritHorns12.wav"] = 363.679432; data["Time002.624.wav"] = 42.958806; data["bell_A3.wav"] = 316.499392; data["gamelan-gong.wav"] = 4236.226573; data["gt_E4.wav"] = 395.857142; data["pno_Eb1.wav"] = 4870.099537; data["silence.wav"] = 0.000000; data["vln_A3.wav"] = 5176.937709; data["vln_D5.wav"] = 3730.424440; data["whitenoise.wav"] = 1482.633870; mDescriptors->AddEnergy(); assertDescriptorExtractionInsideTolerance(data,tolerance, &CLAM::AudioDescriptors::GetEnergy); } void testDecrease() { CLAM::TData tolerance = 0.001; // Due to numerical inaccuracies std::map data; data["AltoSax-Iowa-ff-Db3B3-Region 012.wav"] = -1.229580; data["Balance000.600.wav"] = -4.107201; data["Balance000.992.wav"] = -7.823889; data["Balance001.988.wav"] = -3.630962; data["Balance010.910.wav"] = -6.836714; data["Cello_A2.wav"] = -1.477162; data["Cello_C2.wav"] = -0.466605; data["Disco_Rojo001.008.wav"] = -0.347480; data["Disco_Rojo002.327.wav"] = -1.109347; data["Geiger_Counter005.020.wav"] = -8.500433; data["SaxBritHorns12.wav"] = -23.568533; data["Time002.624.wav"] = -1.077993; data["bell_A3.wav"] = -0.239008; data["gamelan-gong.wav"] = -0.224273; data["gt_E4.wav"] = -0.830142; data["pno_Eb1.wav"] = -0.187336; data["silence.wav"] = 0.000000; data["vln_A3.wav"] = -4.458854; data["vln_D5.wav"] = -8.369821; data["whitenoise.wav"] = -0.189161; mDescriptors->AddDecrease(); assertDescriptorExtractionInsideTolerance(data,tolerance, &CLAM::AudioDescriptors::GetDecrease); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/DescriptorsTests/DescriptionScopeTest.cxx0000644000000000000000000001310410610720021024220 0ustar rootroot/* * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "cppUnitHelper.hxx" #include "DescriptionScope.hxx" // CLAM #include "DataTypes.hxx" // CLAM namespace CLAMTest { class DescriptionScopeTest; CPPUNIT_TEST_SUITE_REGISTRATION( DescriptionScopeTest ); class DescriptionScopeTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( DescriptionScopeTest ); CPPUNIT_TEST( testGetIndex_whenEmpty ); CPPUNIT_TEST( testGetIndex_withOneInserted ); CPPUNIT_TEST( testGetIndex_withAWrongName ); CPPUNIT_TEST( testGetIndex_withSecondInsertedArray ); CPPUNIT_TEST( testAddAttribute_whenNameAlreadyAdded ); CPPUNIT_TEST( testAdding_DifferentTypes ); CPPUNIT_TEST( testCheckType_withOtherType ); CPPUNIT_TEST( testCheckType_withSameType ); CPPUNIT_TEST( testGetAttributeName_withTwoScopes ); CPPUNIT_TEST( testGetAttributeName_withWrongNumber ); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: void testGetIndex_whenEmpty() { CLAM::DescriptionScope spec("TestScope"); try { spec.GetIndex("MyAttribute"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { std::string expected = "Accessing an unexisting attribute 'TestScope':'MyAttribute'"; CPPUNIT_ASSERT_EQUAL( expected, std::string(err.what())); } CPPUNIT_ASSERT_EQUAL(0u,spec.GetNAttributes()); } void testGetIndex_withOneInserted() { CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); CPPUNIT_ASSERT_EQUAL(0u,spec.GetIndex("MyAttribute")); CPPUNIT_ASSERT_EQUAL(1u,spec.GetNAttributes()); } void testGetIndex_withAWrongName() { CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); try { spec.GetIndex("Foo"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { std::string expected = "Accessing an unexisting attribute 'TestScope':'Foo'"; CPPUNIT_ASSERT_EQUAL( expected, std::string(err.what())); } CPPUNIT_ASSERT_EQUAL(1u,spec.GetNAttributes()); } void testGetIndex_withSecondInsertedArray() { CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); spec.Add("Foo"); CPPUNIT_ASSERT_EQUAL(0u,spec.GetIndex("MyAttribute")); CPPUNIT_ASSERT_EQUAL(1u,spec.GetIndex("Foo")); CPPUNIT_ASSERT_EQUAL(2u,spec.GetNAttributes()); } void testAddAttribute_whenNameAlreadyAdded() { CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); try { spec.Add("MyAttribute"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { std::string expected = "Couldn't add attribute 'TestScope:MyAttribute', already present in the scope"; CPPUNIT_ASSERT_EQUAL( expected, std::string(err.what())); } CPPUNIT_ASSERT_EQUAL(1u,spec.GetNAttributes()); } void testAdding_DifferentTypes() { CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); spec.Add("Foo"); CPPUNIT_ASSERT_EQUAL(0u,spec.GetIndex("MyAttribute")); CPPUNIT_ASSERT_EQUAL(1u,spec.GetIndex("Foo")); CPPUNIT_ASSERT_EQUAL(2u,spec.GetNAttributes()); } void testCheckType_withOtherType() { CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); try { spec.CheckType(0,(CLAM::TIndex*)0); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { std::string expected = std::string("Attribute 'TestScope:MyAttribute' has been used as type '") + typeid(int).name() + "' but it really was of type '" + typeid(float).name() + "'"; CPPUNIT_ASSERT_EQUAL( expected, std::string(err.what())); } } void testCheckType_withSameType() { CLAM::DescriptionScope spec("TestScope"); spec.Add("MyAttribute"); spec.CheckType(0,(CLAM::TData*)0); } void testGetAttributeName_withTwoScopes() { CLAM::DescriptionScope scope("TestScope"); scope.Add< CLAM::TData >("MyAttribute"); scope.Add< CLAM::TData >("YourAttribute"); CPPUNIT_ASSERT_EQUAL(std::string("MyAttribute"), scope.GetAttributeName(0)); CPPUNIT_ASSERT_EQUAL(std::string("YourAttribute"), scope.GetAttributeName(1)); } void testGetAttributeName_withWrongNumber() { CLAM::DescriptionScope scope("TestScope"); scope.Add< CLAM::TData >("MyAttribute"); try { scope.GetAttributeName(1); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "GetAttributeName: Using a wrong index to look up an attribute name"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/DescriptorsTests/SpectralDescriptorsTest.cxx0000644000000000000000000004770310610720021024756 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "cppUnitHelper.hxx" #include "SpectralDescriptors.hxx" // CLAM #include "Spectrum.hxx" // CLAM #include "FFT.hxx" // CLAM #include "SpecTypeFlags.hxx" // CLAM #include "AudioFile.hxx" // CLAM #include "MonoAudioFileReader.hxx" // CLAM #include "XMLStorage.hxx" // CLAM #include #include namespace CLAMTest { class SpectralDescriptorsTest; CPPUNIT_TEST_SUITE_REGISTRATION( SpectralDescriptorsTest ); class SpectralDescriptorsTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( SpectralDescriptorsTest ); CPPUNIT_TEST( testDataAttachment_whenLogDataFails ); CPPUNIT_TEST( testConstructionDataAttachment_whenLogDataFails ); CPPUNIT_TEST( testRolloff ); CPPUNIT_TEST( testFlatness ); CPPUNIT_TEST( testCentroid ); // CPPUNIT_TEST( testSpread ); // TODO: fix CPPUNIT_TEST( testSlope ); CPPUNIT_TEST( testMaxMagFreq ); CPPUNIT_TEST( testMagnitudeSkewness ); CPPUNIT_TEST( testMagnitudeKurtosis ); CPPUNIT_TEST( testHighFrequencyContent ); CPPUNIT_TEST_SUITE_END(); private: public: /// Common initialization, executed before each test method void setUp() { mPathToTestData = GetTestDataDirectory("descriptorsData/frames/"); mDescriptors = new CLAM::SpectralDescriptors(); mDescriptors->RemoveAll(); } /// Common clean up, executed after each test method void tearDown() { delete mDescriptors; } private: CLAM::SpectralDescriptors *mDescriptors; std::string mPathToTestData; CLAM::Spectrum ComputeSpectrum(const CLAM::Audio& audioData) { const CLAM::TSize spectrumSize = audioData.GetSize()/2 + 1; // Configure and create the spectrum CLAM::SpecTypeFlags specFlags; specFlags.bMagPhase = 1; CLAM::Spectrum mySpectrum; mySpectrum.SetType(specFlags); mySpectrum.SetSize(spectrumSize); // Configure the transform CLAM::FFTConfig FFTCfg; FFTCfg.SetAudioSize(audioData.GetSize()); // Compute the transform CLAM::FFT myFFT; myFFT.Configure(FFTCfg); myFFT.Start(); myFFT.Do(audioData, mySpectrum); myFFT.Stop(); // Return the result return mySpectrum; } CLAM::Audio ReadAudio(const std::string & fileName) { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile(fileName); CLAM::MonoAudioFileReader reader; bool configOk = reader.Configure(cfg); CPPUNIT_ASSERT_MESSAGE( "configuration failed " + reader.GetConfigErrorMessage(), configOk); CLAM::Audio buf; buf.SetSize(1025); reader.Start(); reader.Do( buf ); reader.Stop(); return buf; } CLAM::Spectrum helperGetData(const std::string & fileName) { std::string extension = fileName.substr(fileName.size()-4,fileName.size()); if (extension!=".xml") { std::string fullPath = mPathToTestData+fileName; return ComputeSpectrum(ReadAudio(fullPath)); } std::string fullPath = mPathToTestData+"Spectrums/"+fileName; CLAM::Spectrum spectrum; CLAM::XMLStorage::Restore(spectrum,fullPath); return spectrum; } void assertDescriptorExtractionInsideTolerance(const std::map & expected, CLAM::TData tolerance, CLAM::TData & (CLAM::SpectralDescriptors::*getter)() const ) { std::stringstream log; bool success = true; mDescriptors->UpdateData(); CLAM::Spectrum spectrum; std::map::const_iterator it; for (it = expected.begin(); it != expected.end(); it++) { spectrum = helperGetData((*it).first); mDescriptors->SetpSpectrum(&spectrum); // CLAM::XMLStorage::Dump(spectrum, "Spectrum", mPathToTestData + "Spectrums/ + it->first + "-Spectrum.xml"); mDescriptors->Compute(); if ( (std::isnan((mDescriptors->*getter)()) != std::isnan(it->second)) || (std::isinf((mDescriptors->*getter)()) != std::isinf(it->second)) || (mDescriptors->*getter)() > (*it).second + tolerance || (mDescriptors->*getter)() < (*it).second - tolerance ) { log << (*it).first << ": expected " << std::setprecision(15) << it->second << ", received " << std::setprecision(15) << (mDescriptors->*getter)() << ", difference " << std::setprecision(15) << (it->second - (mDescriptors->*getter)()) << std::endl; success = false; } } CPPUNIT_ASSERT_MESSAGE(std::string("Error margins surpassed:\n")+log.str() ,success); } private: void testDataAttachment_whenLogDataFails() { CLAM::Spectrum spectrum; spectrum = helperGetData("whitenoise.wav"); spectrum.SetScale(CLAM::EScale::eLog); try { mDescriptors->SetpSpectrum(&spectrum); CPPUNIT_FAIL("Should have thrown an exception"); } catch (const CLAM::ErrAssertionFailed & e) { std::string msg = e.what(); CPPUNIT_ASSERT_EQUAL(std::string("Spectral Descriptors require a linear magnitude Spectrum"), std::string(e.what())); } } void testConstructionDataAttachment_whenLogDataFails() { CLAM::Spectrum spectrum; spectrum = helperGetData("whitenoise.wav"); spectrum.SetScale(CLAM::EScale::eLog); try { CLAM::SpectralDescriptors spectrumDescriptors(&spectrum); CPPUNIT_FAIL("Should have thrown an exception"); } catch (const CLAM::ErrAssertionFailed & e) { std::string msg = e.what(); CPPUNIT_ASSERT_EQUAL(std::string("Spectral Descriptors require a linear magnitude Spectrum"), std::string(e.what())); } } void testRolloff() { CLAM::TData tolerance = 0.0001; // Due to numerical inaccuracies std::map data; data["DeltasAtExtremeBins-Spectrum.xml"] = 22050; data["DeltaAtCenterBin-Spectrum.xml"] = 3*22050.0/(513-1); data["DeltaAtZeroBin-Spectrum.xml"] = 0.0; data["Silence-Spectrum.xml"] = 0.0; data["Constant-Spectrum.xml"] = (513*85/100)*22050.0/(513-1); data["ConstantDouble-Spectrum.xml"] = (513*85/100)*22050.0/(513-1); data["ConstantHalfSize-Spectrum.xml"] = (257*85/100)*22050.0/(257-1); data["AltoSax-Iowa-ff-Db3B3-Region 012.wav"] = 473.73046875; data["Balance000.600.wav"] = 129.19921875; data["Balance000.992.wav"] = 215.33203125; data["Balance001.988.wav"] = 904.39453125; data["Balance010.910.wav"] = 172.265625; data["Cello_A2.wav"] = 1679.58984375; data["Cello_C2.wav"] = 0.000000; data["Disco_Rojo001.008.wav"] = 4909.5703125; data["Disco_Rojo002.327.wav"] = 516.796875; data["Geiger_Counter005.020.wav"] = 258.3984375; data["SaxBritHorns12.wav"] = 2713.18359375; data["Time002.624.wav"] = 9905.2734375; data["bell_A3.wav"] = 2670.1171875; data["gamelan-gong.wav"] = 129.19921875; data["gt_E4.wav"] = 215.33203125; data["pno_Eb1.wav"] = 0.000000; data["silence.wav"] = 0.000000; data["vln_A3.wav"] = 0.000000; data["vln_D5.wav"] = 0.000000; data["whitenoise.wav"] = 18776.953125; mDescriptors->AddRolloff(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralDescriptors::GetRolloff); } void testFlatness() { CLAM::TData tolerance = 0.1; // Due to numerical inaccuracies std::map data; data["DeltasAtExtremeBins-Spectrum.xml"] = 0.0; data["DeltaAtCenterBin-Spectrum.xml"] = 0.0; data["DeltaAtZeroBin-Spectrum.xml"] = 0.0; // Avoid NaN data["Silence-Spectrum.xml"] = 1.0; // Avoid NaN data["Constant-Spectrum.xml"] = 1.0; data["ConstantDouble-Spectrum.xml"] = 1.0; data["ConstantHalfSize-Spectrum.xml"] = 1.0; data["AltoSax-Iowa-ff-Db3B3-Region 012.wav"] = 0.267271624236802; data["Balance000.600.wav"] = 0.036650885546594; data["Balance000.992.wav"] = 0.072583091070888; data["Balance001.988.wav"] = 0.0837806358257842; data["Balance010.910.wav"] = 0.327493037556974; data["Cello_A2.wav"] = 0.277396357995771; data["Cello_C2.wav"] = 1.000000; data["Disco_Rojo001.008.wav"] = 0.322437144838621; data["Disco_Rojo002.327.wav"] = 0.203485263744029; data["Geiger_Counter005.020.wav"] = 0.196482850099661; data["SaxBritHorns12.wav"] = 0.357219109955712; data["Time002.624.wav"] = 0.401771638263218; data["bell_A3.wav"] = 0.288621683607595; data["gamelan-gong.wav"] = 0.303649201938523; data["gt_E4.wav"] = 0.457328853208041; data["pno_Eb1.wav"] = 1.000000; data["silence.wav"] = 1.000000; data["vln_A3.wav"] = 1.000000; data["vln_D5.wav"] = 1.000000; data["whitenoise.wav"] = 0.841145650951002; mDescriptors->AddFlatness(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralDescriptors::GetFlatness); } void testCentroid() { CLAM::TData tolerance = 0.007; // Due to numerical inaccuracies std::map data; data["DeltasAtExtremeBins-Spectrum.xml"] = 11025; data["DeltaAtCenterBin-Spectrum.xml"] = 3*22050.0/(513-1); data["DeltaAtZeroBin-Spectrum.xml"] = 0.0; // Avoid NaN data["Silence-Spectrum.xml"] = 11025; // Avoid NaN data["Constant-Spectrum.xml"] = 11025; data["ConstantDouble-Spectrum.xml"] = 11025; data["ConstantHalfSize-Spectrum.xml"] = 11025; data["AltoSax-Iowa-ff-Db3B3-Region 012.wav"] = 2474.50537340967; data["Balance000.600.wav"] = 441.43828410591; data["Balance000.992.wav"] = 793.86035277716; data["Balance001.988.wav"] = 1545.65773828789; data["Balance010.910.wav"] = 2693.41226047632; data["Cello_A2.wav"] = 3005.95204227151; data["Cello_C2.wav"] = 11025.; data["Disco_Rojo001.008.wav"] = 4208.65401772965; data["Disco_Rojo002.327.wav"] = 2575.172793503; data["Geiger_Counter005.020.wav"] = 1750.98161715738; data["SaxBritHorns12.wav"] = 3847.36074949493; data["Time002.624.wav"] = 7128.46724514185; data["bell_A3.wav"] = 3624.55943759231; data["gamelan-gong.wav"] = 1278.48982559027; data["gt_E4.wav"] = 4486.20249063408; // Silences data["pno_Eb1.wav"] = 11025.; data["silence.wav"] = 11025.; data["vln_A3.wav"] = 11025.; data["vln_D5.wav"] = 11025.; data["whitenoise.wav"] = 11115.6968494146; mDescriptors->AddCentroid(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralDescriptors::GetCentroid); } CLAM::TData plainSpread(CLAM::TData nBins, CLAM::TData spectralRange) { CLAM::TData binRange = spectralRange/(nBins-1); return binRange*binRange*(nBins+1)*(nBins-1)/12; } void testSpread() { CLAM::TData tolerance = 0.0006; // Due to numerical inaccuracies std::map data; data["DeltasAtExtremeBins-Spectrum.xml"] = 22050*22050/4; data["DeltaAtCenterBin-Spectrum.xml"] = 0.0; data["DeltaAtZeroBin-Spectrum.xml"] = 0.0; // Avoid NaN data["Silence-Spectrum.xml"] = plainSpread(513,22050); // Avoid NaN data["Constant-Spectrum.xml"] = plainSpread(513,22050); data["ConstantDouble-Spectrum.xml"] = plainSpread(513,22050); data["ConstantHalfSize-Spectrum.xml"] = plainSpread(257,22050); data["AltoSax-Iowa-ff-Db3B3-Region 012.wav"] = 19988729.96601; data["Balance000.600.wav"] = 3256552.743; data["Balance000.992.wav"] = 6201384.658; data["Balance001.988.wav"] = 4687203.759; data["Balance010.910.wav"] = 24206724.5216; data["Cello_A2.wav"] = 15697222.546; data["Cello_C2.wav"] = plainSpread(513,22050); data["Disco_Rojo001.008.wav"] = 14805980.3445418; data["Disco_Rojo002.327.wav"] = 11706385.6573933; data["Geiger_Counter005.020.wav"] = 14443489.7393; data["SaxBritHorns12.wav"] = 17017109.5633701; data["Time002.624.wav"] = 25246294.0153; data["bell_A3.wav"] = 15736636.995407; data["gamelan-gong.wav"] = 5662587.598; data["gt_E4.wav"] = 34762401.1; data["pno_Eb1.wav"] = plainSpread(513,22050); data["silence.wav"] = plainSpread(513,22050); data["vln_A3.wav"] = plainSpread(513,22050); data["vln_D5.wav"] = plainSpread(513,22050); data["whitenoise.wav"] = 40201639.326; mDescriptors->AddSpread(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralDescriptors::GetSpread); } void testSlope() { CLAM::TData tolerance = 1e-8; // Due to numerical inaccuracies std::map data; data["DeltaAtZeroBin-Spectrum.xml"] = -5.28363e-07; data["Constant-Spectrum.xml"]= 0.0; data["ConstantDouble-Spectrum.xml"]= 0.0; data["ConstantHalfSize-Spectrum.xml"]= 0.0; data["DeltasAtExtremeBins-Spectrum.xml"]= 0.0; data["DeltaAtCenterBin-Spectrum.xml"]= -5.22171e-07; data["AltoSax-Iowa-ff-Db3B3-Region 012.wav"] = -4.07655e-07; data["Balance000.600.wav"] = -5.10341e-07; data["Balance000.992.wav"] = -4.92062e-07; data["Balance001.988.wav"] = -4.5384e-07; data["Balance010.910.wav"] = -4.00459e-07; data["Cello_A2.wav"] = -3.8499e-07; data["Cello_C2.wav"] = 0; data["Disco_Rojo001.008.wav"] = -3.29443e-07; data["Disco_Rojo002.327.wav"] = -4.06101e-07; data["Geiger_Counter005.020.wav"] = -4.45345e-07; data["SaxBritHorns12.wav"] = -3.49636e-07; data["Time002.624.wav"] = -1.86454e-07; data["bell_A3.wav"] = -3.52736e-07; data["gamelan-gong.wav"] = -8.17134e-07; data["gt_E4.wav"] = -3.18173e-07; data["pno_Eb1.wav"] = 0; data["silence.wav"] = 0; data["vln_A3.wav"] = 0; data["vln_D5.wav"] = 0; data["whitenoise.wav"] = 3.34021e-09; mDescriptors->AddSlope(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralDescriptors::GetSlope); } void testMaxMagFreq() { CLAM::TData tolerance = 1; // Due to numerical inaccuracies, 1 Hz std::map data; data["DeltaAtZeroBin-Spectrum.xml"] = 0.0; data["Constant-Spectrum.xml"]= 0.0; data["ConstantDouble-Spectrum.xml"]= 0.0; data["ConstantHalfSize-Spectrum.xml"]= 0.0; data["DeltasAtExtremeBins-Spectrum.xml"]= 0.0; data["DeltaAtCenterBin-Spectrum.xml"]= 129.19921875; data["AltoSax-Iowa-ff-Db3B3-Region 012.wav"] = 258.3984; data["Balance000.600.wav"] = 129.1992; data["Balance000.992.wav"] = 215.3320; data["Balance001.988.wav"] = 602.9296; data["Balance010.910.wav"] = 86.1328; data["Cello_A2.wav"] = 861.3280; data["Cello_C2.wav"] = 0; data["Disco_Rojo001.008.wav"] = 43.06647; data["Disco_Rojo002.327.wav"] = 86.1328; data["Geiger_Counter005.020.wav"] = 129.1992; data["SaxBritHorns12.wav"] = 1981.1; data["Time002.624.wav"] = 6373.8; data["bell_A3.wav"] = 2153.3; data["gamelan-gong.wav"] = 129.199; data["gt_E4.wav"] = 43.0664; data["pno_Eb1.wav"] = 0; data["silence.wav"] = 0; data["vln_A3.wav"] = 0; data["vln_D5.wav"] = 0; data["whitenoise.wav"] = 12791; mDescriptors->AddMaxMagFreq(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralDescriptors::GetMaxMagFreq); } void testMagnitudeSkewness() { CLAM::TData tolerance = 0.001; // Due to numerical inaccuracies std::map data; data["DeltaAtZeroBin-Spectrum.xml"] = 22.5830516815186; data["Constant-Spectrum.xml"]= 0.0; data["ConstantDouble-Spectrum.xml"]= 0.0; data["ConstantHalfSize-Spectrum.xml"]= 0.0; // Avoid NaN data["DeltasAtExtremeBins-Spectrum.xml"]= 15.9218053817749; data["DeltaAtCenterBin-Spectrum.xml"]= 22.5830516815186; data["AltoSax-Iowa-ff-Db3B3-Region 012.wav"] = 8.40675163269043; data["Balance000.600.wav"] = 18.5365924835205; data["Balance000.992.wav"] = 21.5264225006104; data["Balance001.988.wav"] = 6.5138783454895; data["Balance010.910.wav"] = 14.1958694458008; data["Cello_A2.wav"] = 7.86557388305664; data["Cello_C2.wav"] = 0.000000; // Avoid NaN!! data["Disco_Rojo001.008.wav"] = 3.03432536125183; data["Disco_Rojo002.327.wav"] = 9.71939277648926; data["Geiger_Counter005.020.wav"] = 10.891640663147; data["SaxBritHorns12.wav"] = 4.83596897125244; data["Time002.624.wav"] = 4.86174297332764; data["bell_A3.wav"] = 8.53497505187988; data["gamelan-gong.wav"] = 13.2020807266235; data["gt_E4.wav"] = 15.7197198867798; data["pno_Eb1.wav"] = 0.000000; // Avoid NaN!! data["silence.wav"] = 0.000000; // Avoid NaN!! data["vln_A3.wav"] = 0.000000; // Avoid NaN!! data["vln_D5.wav"] = 0.000000; // Avoid NaN!! data["whitenoise.wav"] = 0.401344895362854; mDescriptors->AddMagnitudeSkewness(); assertDescriptorExtractionInsideTolerance(data,tolerance, &CLAM::SpectralDescriptors::GetMagnitudeSkewness); } void testMagnitudeKurtosis() { CLAM::TData tolerance = 0.008; // Due to numerical inaccuracies std::map data; data["DeltaAtZeroBin-Spectrum.xml"] = 510.994171142578; data["Silence-Spectrum.xml"] = 3.0; // Avoid NaN data["Constant-Spectrum.xml"]= 3.0; data["ConstantDouble-Spectrum.xml"]= 3.0; data["ConstantHalfSize-Spectrum.xml"]= 3.0; data["DeltasAtExtremeBins-Spectrum.xml"]= 254.503921508789; data["DeltaAtCenterBin-Spectrum.xml"]= 510.994232177734; data["AltoSax-Iowa-ff-Db3B3-Region 012.wav"] = 82.7926788330078; data["Balance000.600.wav"] = 377.411987304688; data["Balance000.992.wav"] = 477.992065429688; data["Balance001.988.wav"] = 53.0362358093262; data["Balance010.910.wav"] = 238.156997680664; data["Cello_A2.wav"] = 93.5747756958008; data["Cello_C2.wav"] = 3.000000; // Avoid NaN!! data["Disco_Rojo001.008.wav"] = 16.8839492797852; data["Disco_Rojo002.327.wav"] = 128.505096435547; data["Geiger_Counter005.020.wav"] = 140.091598510742; data["SaxBritHorns12.wav"] = 32.0153884887695; data["Time002.624.wav"] = 33.4215717315674; data["bell_A3.wav"] = 87.1860504150391; data["gamelan-gong.wav"] = 191.309326171875; data["gt_E4.wav"] = 296.318389892578; data["pno_Eb1.wav"] = 3.000000; // Avoid NaN!! data["silence.wav"] = 3.000000; // Avoid NaN!! data["vln_A3.wav"] = 3.000000; // Avoid NaN!! data["vln_D5.wav"] = 3.000000; // Avoid NaN!! data["whitenoise.wav"] = 2.48478102684021; mDescriptors->AddMagnitudeKurtosis(); assertDescriptorExtractionInsideTolerance(data,tolerance, &CLAM::SpectralDescriptors::GetMagnitudeKurtosis); } void testHighFrequencyContent() { // TODO find out why we obtain so different precisions in different boxes // This low tolerance works with David's laptop (April 4th 2005) // CLAM::TData tolerance = 0.00000000000008; // Due to numerical inaccuracies // This tolerance is set in order to pass tests in Pau's desktop (the auto-tests box) CLAM::TData tolerance = 0.063; // Due to numerical inaccuracies std::map data; data["DeltaAtZeroBin-Spectrum.xml"] = 0.0; // Magnitude * 0 data["Silence-Spectrum.xml"] = 0.0; // Silence data["Constant-Spectrum.xml"]= 131328.0; // 1^2 * sum(1 to 512) data["ConstantDouble-Spectrum.xml"]= 21012480000.0; // 400^2 * sum(1 to 512) data["ConstantHalfSize-Spectrum.xml"]= 526336.0; data["DeltasAtExtremeBins-Spectrum.xml"]= 512.0; // 1.0^2 * 512 data["DeltaAtCenterBin-Spectrum.xml"]= 3.0; // 1.0^2 * 3 (the 4th bin) data["AltoSax-Iowa-ff-Db3B3-Region 012.wav"] = 1470.23229980469; data["Balance000.600.wav"] = 35030.921875; data["Balance000.992.wav"] = 35163.140625; data["Balance001.988.wav"] = 112741.8125; data["Balance010.910.wav"] = 67255.7421875; data["Cello_A2.wav"] = 442392.4375; data["Cello_C2.wav"] = 0.0; // Silence data["Disco_Rojo001.008.wav"] = 932898.0625; data["Disco_Rojo002.327.wav"] = 237543.015625; data["Geiger_Counter005.020.wav"] = 47262.77734375; data["SaxBritHorns12.wav"] = 510716.90625; data["Time002.624.wav"] = 660661.875; data["bell_A3.wav"] = 557884.6875; data["gamelan-gong.wav"] = 722027.0625; data["gt_E4.wav"] = 5.25228691101074; data["pno_Eb1.wav"] = 0.000000; // Silence data["silence.wav"] = 0.000000; // Silence data["vln_A3.wav"] = 0.000000; // Silence data["vln_D5.wav"] = 0.000000; // Silence data["whitenoise.wav"] = 44574532.0; mDescriptors->AddHighFrequencyContent(); assertDescriptorExtractionInsideTolerance(data,tolerance, &CLAM::SpectralDescriptors::GetHighFrequencyContent); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/DescriptorsTests/DescriptionSchemeTest.cxx0000644000000000000000000001607210610720021024362 0ustar rootroot/* * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "cppUnitHelper.hxx" #include "DescriptionScheme.hxx" // CLAM #include "DataTypes.hxx" // CLAM #include "Component.hxx" // CLAM #include "XMLStorage.hxx" // CLAM namespace CLAMTest { class DescriptionSchemeTest; CPPUNIT_TEST_SUITE_REGISTRATION( DescriptionSchemeTest ); class DescriptionSchemeTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( DescriptionSchemeTest ); CPPUNIT_TEST( testGetNScopes_withNoScopeRegistered ); CPPUNIT_TEST( testGetNScopes_withASingleAttribute ); CPPUNIT_TEST( testGetNScopes_withTwoAttributeOnDifferentScopes ); CPPUNIT_TEST( testGetNScopes_withTwoAttributeOnTheSameScope ); CPPUNIT_TEST( testGetScope_withNoScopeRegistered ); CPPUNIT_TEST( testGetScope_withARegisteredAttribute ); CPPUNIT_TEST( testGetScope_withTwoScopes ); CPPUNIT_TEST( testGetScopeByIndex_withIndexOutOfBounds ); CPPUNIT_TEST( testGetScopeIndex_withNoScopeRegistered ); CPPUNIT_TEST( testGetScopeIndex_withARegisteredAttribute ); CPPUNIT_TEST( testGetScopeIndex_withTwoScopes ); CPPUNIT_TEST( testGetScopeName_withTwoScopes ); CPPUNIT_TEST( testGetScopeName_withWrongNumber ); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: void testGetNScopes_withNoScopeRegistered() { CLAM::DescriptionScheme scheme; CPPUNIT_ASSERT_EQUAL(0u, scheme.GetNScopes()); } void testGetNScopes_withASingleAttribute() { CLAM::DescriptionScheme scheme; scheme.AddAttribute("MyScope","MyAttribute"); CPPUNIT_ASSERT_EQUAL(1u, scheme.GetNScopes()); } void testGetNScopes_withTwoAttributeOnDifferentScopes() { CLAM::DescriptionScheme scheme; scheme.AddAttribute("MyScope","MyAttribute"); scheme.AddAttribute("YourScope","YourAttribute"); CPPUNIT_ASSERT_EQUAL(2u, scheme.GetNScopes()); } void testGetNScopes_withTwoAttributeOnTheSameScope() { CLAM::DescriptionScheme scheme; scheme.AddAttribute("MyScope","MyAttribute"); scheme.AddAttribute("MyScope","YourAttribute"); CPPUNIT_ASSERT_EQUAL(1u, scheme.GetNScopes()); } void testGetScope_withNoScopeRegistered() { CLAM::DescriptionScheme scheme; try { scheme.GetScope("NonExistent"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Attribute scope 'NonExistent' not found"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testGetScope_withARegisteredAttribute() { CLAM::DescriptionScheme scheme; scheme.AddAttribute("MyScope","MyAttribute"); scheme.AddAttribute("MyScope","MyOtherAttribute"); const CLAM::DescriptionScope & spec = scheme.GetScope("MyScope"); CPPUNIT_ASSERT_EQUAL(0u,spec.GetIndex("MyAttribute")); CPPUNIT_ASSERT_EQUAL(1u,spec.GetIndex("MyOtherAttribute")); } void testGetScope_withTwoScopes() { CLAM::DescriptionScheme scheme; scheme.AddAttribute("MyScope","MyAttribute"); scheme.AddAttribute("YourScope","YourAttribute"); scheme.AddAttribute("YourScope","YourIntAttribute"); const CLAM::DescriptionScope & myScope = scheme.GetScope("MyScope"); const CLAM::DescriptionScope & yourScope = scheme.GetScope("YourScope"); CPPUNIT_ASSERT_EQUAL(0u,myScope.GetIndex("MyAttribute")); CPPUNIT_ASSERT_EQUAL(0u,yourScope.GetIndex("YourAttribute")); CPPUNIT_ASSERT_EQUAL(1u,yourScope.GetIndex("YourIntAttribute")); } void testGetScopeByIndex_withIndexOutOfBounds() { CLAM::DescriptionScheme scheme; try { scheme.GetScope(0); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Accessing an illegal scope index for the description scheme"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testGetScopeIndex_withNoScopeRegistered() { CLAM::DescriptionScheme scheme; try { scheme.GetScopeIndex("NonExistent"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Attribute scope 'NonExistent' not found"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testGetScopeIndex_withARegisteredAttribute() { CLAM::DescriptionScheme scheme; scheme.AddAttribute("MyScope","MyAttribute"); scheme.AddAttribute("MyScope","MyOtherAttribute"); unsigned scopeIndex = scheme.GetScopeIndex("MyScope"); const CLAM::DescriptionScope & scope = scheme.GetScope(scopeIndex); CPPUNIT_ASSERT_EQUAL(0u,scope.GetIndex("MyAttribute")); CPPUNIT_ASSERT_EQUAL(1u,scope.GetIndex("MyOtherAttribute")); } void testGetScopeIndex_withTwoScopes() { CLAM::DescriptionScheme scheme; scheme.AddAttribute("MyScope","MyAttribute"); scheme.AddAttribute("YourScope","YourAttribute"); scheme.AddAttribute("YourScope","YourIntAttribute"); unsigned myScopeIndex = scheme.GetScopeIndex("MyScope"); const CLAM::DescriptionScope & myScope = scheme.GetScope(myScopeIndex); unsigned yourScopeIndex = scheme.GetScopeIndex("YourScope"); const CLAM::DescriptionScope & yourScope = scheme.GetScope(yourScopeIndex); CPPUNIT_ASSERT_EQUAL(0u,myScope.GetIndex("MyAttribute")); CPPUNIT_ASSERT_EQUAL(0u,yourScope.GetIndex("YourAttribute")); CPPUNIT_ASSERT_EQUAL(1u,yourScope.GetIndex("YourIntAttribute")); } void testGetScopeName_withTwoScopes() { CLAM::DescriptionScheme scheme; scheme.AddAttribute("MyScope","MyAttribute"); scheme.AddAttribute("YourScope","YourAttribute"); CPPUNIT_ASSERT_EQUAL(std::string("MyScope"), scheme.GetScopeName(0)); CPPUNIT_ASSERT_EQUAL(std::string("YourScope"), scheme.GetScopeName(1)); } void testGetScopeName_withWrongNumber() { CLAM::DescriptionScheme scheme; scheme.AddAttribute("MyScope","MyAttribute"); try { scheme.GetScopeName(1); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Accessing an illegal scope index for the description scheme"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/DescriptorsTests/IndirectBindingTest.cxx0000644000000000000000000002061410610720021024003 0ustar rootroot/* * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "cppUnitHelper.hxx" #include "Extractor.hxx" // CLAM #include "DataTypes.hxx" // CLAM namespace CLAMTest { class IndirectBindingTest; CPPUNIT_TEST_SUITE_REGISTRATION( IndirectBindingTest ); class IndirectBindingTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( IndirectBindingTest ); CPPUNIT_TEST(testInit_PointsToThePlaceReferencedByTheFirstReference); CPPUNIT_TEST(testNext_PointsToThePlaceReferencedByTheSecondReference); CPPUNIT_TEST(testIsInsideScope_returnsTrueBeforeEnd); CPPUNIT_TEST(testIsInsideScope_returnsFalseAfterLastReference); CPPUNIT_TEST(testGetForReading_failsWhenInvalidReference); CPPUNIT_TEST(testExtraction_usingHooks); CPPUNIT_TEST(testDoubleIndirection_usingHooks); CPPUNIT_TEST(testRangeInit_PointsToTheFirstRange); CPPUNIT_TEST(testGetRangeForReading_failsWhenInvalidReference); CPPUNIT_TEST(testRangeExtraction_usingHooks); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { mScheme.AddAttribute ( "Referenced","Input"); mScheme.AddAttribute ( "Referenced","ReverseReference"); mScheme.AddAttribute ( "Referencer","BadReference"); mScheme.AddAttribute ( "Referencer","Reference"); mScheme.AddAttribute ( "Referencer","Output"); mScheme.AddAttribute( "Referencer","Concatenations"); mPool = new CLAM::DescriptionDataPool(mScheme); mPool->SetNumberOfContexts("Referenced",10); mPool->SetNumberOfContexts("Referencer",3); { char * inputBuffer = mPool->GetWritePool("Referenced","Input"); for (unsigned i = 0; i<10; i++) inputBuffer[i]='a'+i; } { unsigned * inputBuffer = mPool->GetWritePool("Referenced","ReverseReference"); for (unsigned i = 0; i<10; i++) inputBuffer[i]=9-i; } { unsigned * inputBuffer = mPool->GetWritePool("Referencer","Reference"); for (unsigned i = 0; i<3; i++) inputBuffer[i]=3*i; } { unsigned * inputBuffer = mPool->GetWritePool("Referencer","BadReference"); for (unsigned i = 0; i<3; i++) inputBuffer[i]=3*i; inputBuffer[0]=20; } } /// Common clean up, executed after each test method void tearDown() { delete mPool; } private: CLAM::DescriptionScheme mScheme; CLAM::DescriptionDataPool * mPool; void testInit_PointsToThePlaceReferencedByTheFirstReference() { CLAM::ReadHook hook; hook.Bind("Referenced","Input"); hook.Indirect("Referencer","Reference"); hook.Init(*mPool); const void * result = & (hook.GetForReading()); const void * expected = mPool->GetReadPool("Referenced","Input"); CPPUNIT_ASSERT_EQUAL(expected,result); } void testNext_PointsToThePlaceReferencedByTheSecondReference() { CLAM::ReadHook hook; hook.Bind("Referenced","Input"); hook.Indirect("Referencer","Reference"); hook.Init(*mPool); hook.Next(); const void * result = & (hook.GetForReading()); const void * thirdPosition = mPool->GetReadPool("Referenced","Input")+3; CPPUNIT_ASSERT_EQUAL(thirdPosition,result); } void testIsInsideScope_returnsTrueBeforeEnd() { CLAM::ReadHook hook; hook.Bind("Referenced","Input"); hook.Indirect("Referencer","Reference"); hook.Init(*mPool); CPPUNIT_ASSERT(hook.IsInsideScope()); hook.Next(); CPPUNIT_ASSERT(hook.IsInsideScope()); hook.Next(); CPPUNIT_ASSERT(hook.IsInsideScope()); } void testIsInsideScope_returnsFalseAfterLastReference() { CLAM::ReadHook hook; hook.Bind("Referenced","Input"); hook.Indirect("Referencer","Reference"); hook.Init(*mPool); hook.Next(); hook.Next(); hook.Next(); CPPUNIT_ASSERT(!hook.IsInsideScope()); } void testGetForReading_failsWhenInvalidReference() { CLAM::ReadHook hook; hook.Bind("Referenced","Input"); hook.Indirect("Referencer","BadReference"); hook.Init(*mPool); try { const void * result = & (hook.GetForReading()); CPPUNIT_FAIL("Should have failed an assertion"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Invalid cross-scope reference"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testExtraction_usingHooks() { CLAM::WriteHook outputHook; CLAM::ReadHook inputHook; inputHook.Bind("Referenced","Input"); inputHook.Indirect("Referencer","Reference"); outputHook.Bind("Referencer","Output"); for (inputHook.Init(*mPool),outputHook.Init(*mPool); inputHook.IsInsideScope() && outputHook.IsInsideScope(); outputHook.Next(),inputHook.Next()) { const char & input = inputHook.GetForReading(); char & output = outputHook.GetForWriting(); output = input; } std::string expected("adg",3); std::string result(mPool->GetWritePool("Referencer","Output"),3); CPPUNIT_ASSERT_EQUAL(expected,result); } void testDoubleIndirection_usingHooks() { CLAM::WriteHook outputHook; CLAM::ReadHook inputHook; inputHook.Bind("Referenced","Input"); inputHook.Indirect("Referenced","ReverseReference"); inputHook.Indirect("Referencer","Reference"); outputHook.Bind("Referencer","Output"); for (inputHook.Init(*mPool),outputHook.Init(*mPool); inputHook.IsInsideScope() && outputHook.IsInsideScope(); outputHook.Next(),inputHook.Next()) { const char & input = inputHook.GetForReading(); char & output = outputHook.GetForWriting(); output = input; } std::string expected("jgd",3); std::string result(mPool->GetWritePool("Referencer","Output"),3); CPPUNIT_ASSERT_EQUAL(expected,result); } void testRangeInit_PointsToTheFirstRange() { CLAM::ReadRangedHook hook; hook.Range(4); hook.Bind("Referenced","Input"); hook.Indirect("Referencer","Reference"); hook.Init(*mPool); const char * begin; const char * end; hook.GetRangeForReading(begin,end); const char * expectedBegin = mPool->GetReadPool("Referenced","Input"); const char * expectedEnd = expectedBegin + 4; CPPUNIT_ASSERT_EQUAL( (void*)expectedBegin, (void*)begin); CPPUNIT_ASSERT_EQUAL( (void*)expectedEnd, (void*)end); } void testGetRangeForReading_failsWhenInvalidReference() { CLAM::ReadRangedHook hook; hook.Range(4); hook.Bind("Referenced","Input"); hook.Indirect("Referencer","BadReference"); hook.Init(*mPool); try { const char * begin; const char * end; hook.GetRangeForReading(begin,end); CPPUNIT_FAIL("Should have failed an assertion"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Invalid cross-scope reference"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testRangeExtraction_usingHooks() { CLAM::ReadRangedHook inputHook; inputHook.Range(4); inputHook.Bind("Referenced","Input"); inputHook.Indirect("Referencer","Reference"); CLAM::WriteHook outputHook; outputHook.Bind("Referencer","Concatenations"); for (inputHook.Init(*mPool),outputHook.Init(*mPool); inputHook.IsInsideScope() && outputHook.IsInsideScope(); outputHook.Next(),inputHook.Next()) { const char * input; const char * inputEnd; inputHook.GetRangeForReading(input, inputEnd); std::string & output = outputHook.GetForWriting(); for (output = ""; inputGetWritePool("Referencer","Concatenations"); CPPUNIT_ASSERT_EQUAL(expected0,results[0]); CPPUNIT_ASSERT_EQUAL(expected1,results[1]); CPPUNIT_ASSERT_EQUAL(expected2,results[2]); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/DescriptorsTests/DescriptionDataPoolTest.cxx0000644000000000000000000001777410610720021024673 0ustar rootroot/* * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "cppUnitHelper.hxx" #include "Pool.hxx" // CLAM #include "DataTypes.hxx" // CLAM namespace CLAMTest { class DescriptionDataPoolTest; CPPUNIT_TEST_SUITE_REGISTRATION( DescriptionDataPoolTest ); class DescriptionDataPoolTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( DescriptionDataPoolTest ); CPPUNIT_TEST( testUnpopulatedScopeIsNotFreed ); CPPUNIT_TEST( testSetNumberOfContexts_withANonExistingScope ); CPPUNIT_TEST( testInstanciateAttribute_withinUnexistingScope ); CPPUNIT_TEST( testInstanciateAttribute_withinUnpopulatedScope ); CPPUNIT_TEST( testInstanciateAttribute_whenTheAttributeDoesNotExist ); CPPUNIT_TEST( testInstanciateAttribute_whenTheAttributeDoesNotExistButTheScopeIsNotPopulated ); CPPUNIT_TEST( testGetAttribute_withDifferentAttributes ); CPPUNIT_TEST( testGetAttribute_withTheSameAttributeTwice ); CPPUNIT_TEST( testGetAttribute_fromAUnpopulatedScope ); CPPUNIT_TEST( testGetAttribute_fromUnexistingScope ); CPPUNIT_TEST( testGetAttribute_withNonInstantiatedAttribute ); CPPUNIT_TEST( testInsertElement ); CPPUNIT_TEST( testRemoveElement ); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { mScheme.AddAttribute ("AudioSample","Level"); mScheme.AddAttribute ("Frame","Center"); mScheme.AddAttribute ("Frame","Size"); mScheme.AddAttribute ("Frame","MyLabel"); } /// Common clean up, executed after each test method void tearDown() { } private: CLAM::DescriptionScheme mScheme; private: void testUnpopulatedScopeIsNotFreed() { CLAM::DescriptionDataPool data(mScheme); // Should not be a memory leak } void testSetNumberOfContexts_withANonExistingScope() { CLAM::DescriptionDataPool data(mScheme); try { data.SetNumberOfContexts("NonExistingScope",10); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Attribute scope 'NonExistingScope' not found"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testInstanciateAttribute_withinUnexistingScope() { CLAM::DescriptionDataPool data(mScheme); try { data.InstantiateAttribute("UnexistingScope","Center"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Attribute scope 'UnexistingScope' not found"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testInstanciateAttribute_withinUnpopulatedScope() { CLAM::DescriptionDataPool data(mScheme); try { data.InstantiateAttribute("Frame","Center"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Instantianting 'Frame:Center' but the scope is not yet populated"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testInstanciateAttribute_whenTheAttributeDoesNotExist() { CLAM::DescriptionDataPool data(mScheme); data.SetNumberOfContexts("Frame",10); try { data.InstantiateAttribute("Frame","UnexistingAttribute"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Accessing an unexisting attribute 'Frame':'UnexistingAttribute'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testInstanciateAttribute_whenTheAttributeDoesNotExistButTheScopeIsNotPopulated() { CLAM::DescriptionDataPool data(mScheme); try { data.InstantiateAttribute("Frame","UnexistingAttribute"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Accessing an unexisting attribute 'Frame':'UnexistingAttribute'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testGetAttribute_withDifferentAttributes() { CLAM::DescriptionDataPool data(mScheme); data.SetNumberOfContexts("Frame",30); data.InstantiateAttribute("Frame","Center"); data.InstantiateAttribute("Frame","Size"); unsigned * centers = data.GetWritePool("Frame","Center"); unsigned * sizes = data.GetWritePool("Frame","Size"); CPPUNIT_ASSERT(centers!=sizes); } void testGetAttribute_withTheSameAttributeTwice() { CLAM::DescriptionDataPool data(mScheme); data.SetNumberOfContexts("Frame",30); data.InstantiateAttribute("Frame","Center"); unsigned * centers = data.GetWritePool("Frame","Center"); unsigned * centers2 = data.GetWritePool("Frame","Center"); CPPUNIT_ASSERT_EQUAL(centers,centers2); } void testGetAttribute_fromAUnpopulatedScope() { CLAM::DescriptionDataPool data(mScheme); try { data.GetWritePool("Frame","Center"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Writting data on 'Frame:Center' but the scope is not yet populated"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testGetAttribute_fromUnexistingScope() { CLAM::DescriptionDataPool data(mScheme); try { data.GetWritePool("UnexistingScope","Center"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Attribute scope 'UnexistingScope' not found"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testGetAttribute_withNonInstantiatedAttribute() { CLAM::DescriptionDataPool data(mScheme); data.SetNumberOfContexts("Frame",30); try { data.GetReadPool("Frame","Center"); CPPUNIT_FAIL("Should have thrown an exception"); } catch (CLAM::ErrAssertionFailed & err) { const std::string expected = "Getting data from a non instanciated attribute 'Frame':'Center'"; CPPUNIT_ASSERT_EQUAL(expected, std::string(err.what())); } } void testInsertElement() { CLAM::DescriptionDataPool data(mScheme); data.SetNumberOfContexts("Frame",10); { unsigned * centers = data.GetWritePool("Frame","Center"); for (unsigned i=0; i("Frame","Center"); for (unsigned i=0; i("Frame","Center"); for (unsigned i=0; i("Frame","Center"); for (unsigned i=0; i #include "cppUnitHelper.hxx" #include "SpectralPeakDescriptors.hxx" // CLAM #include "SpectralPeakArray.hxx" // CLAM #include "SpectralPeakDetect.hxx" // CLAM #include "Spectrum.hxx" // CLAM #include "FFT.hxx" // CLAM #include "SpecTypeFlags.hxx" // CLAM #include "AudioFile.hxx" // CLAM #include "MonoAudioFileReader.hxx" // CLAM #include "XMLStorage.hxx" // CLAM #include namespace CLAMTest { class SpectralPeakDescriptorsTest; CPPUNIT_TEST_SUITE_REGISTRATION( SpectralPeakDescriptorsTest ); class SpectralPeakDescriptorsTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( SpectralPeakDescriptorsTest ); CPPUNIT_TEST( testDataAttachment_whenLogDataFails ); CPPUNIT_TEST( testConstructionDataAttachment_whenLogDataFails ); CPPUNIT_TEST( testMagnitudeMean ); CPPUNIT_TEST( testHarmonicCentroid ); CPPUNIT_TEST( testHarmonicDeviation ); CPPUNIT_TEST( testFirstTristimulus ); CPPUNIT_TEST( testSecondTristimulus ); CPPUNIT_TEST( testThirdTristimulus ); CPPUNIT_TEST( testOddHarmonics ); CPPUNIT_TEST( testEvenHarmonics ); CPPUNIT_TEST( testOddToEvenRatio ); CPPUNIT_TEST_SUITE_END(); private: public: /// Common initialization, executed before each test method void setUp() { mPathToTestData = GetTestDataDirectory("descriptorsData/frames/SpectralPeaks/"); mDescriptors = new CLAM::SpectralPeakDescriptors(); mDescriptors->RemoveAll(); } /// Common clean up, executed after each test method void tearDown() { delete mDescriptors; } private: CLAM::SpectralPeakDescriptors *mDescriptors; std::string mPathToTestData; CLAM::Spectrum ComputeSpectrum(const CLAM::Audio& audioData) { const CLAM::TSize spectrumSize = audioData.GetSize()/2 + 1; // Configure and create the spectrum CLAM::SpecTypeFlags specFlags; specFlags.bMagPhase = 1; CLAM::Spectrum mySpectrum; mySpectrum.SetType(specFlags); mySpectrum.SetSize(spectrumSize); // Configure the transform CLAM::FFTConfig FFTCfg; FFTCfg.SetAudioSize(audioData.GetSize()); // Compute the transform CLAM::FFT myFFT; myFFT.Configure(FFTCfg); myFFT.Start(); myFFT.Do(audioData, mySpectrum); myFFT.Stop(); // Return the result return mySpectrum; } CLAM::SpectralPeakArray ComputeSpectralPeaks(const CLAM::Spectrum& spectrum) { CLAM::SpectralPeakDetect peakDetect; CLAM::SpectralPeakArray myPeakArray; CLAM::Spectrum dbSpectrum(spectrum); dbSpectrum.ToDB(); myPeakArray.SetScale(CLAM::EScale::eLog); peakDetect.Do(dbSpectrum,myPeakArray); myPeakArray.ToLinear(); return myPeakArray; } CLAM::Audio ReadAudio(const std::string & fileName) { CLAM::MonoAudioFileReaderConfig cfg; cfg.SetSourceFile(fileName); CLAM::MonoAudioFileReader reader; bool configOk = reader.Configure(cfg); CPPUNIT_ASSERT_MESSAGE( "configuration failed " + reader.GetConfigErrorMessage(), configOk); CLAM::Audio buf; buf.SetSize(1025); reader.Start(); reader.Do( buf ); reader.Stop(); return buf; } CLAM::SpectralPeakArray helperGetData(const std::string & fileName) { std::string extension = fileName.substr(fileName.size()-4,fileName.size()); std::string fullPath = mPathToTestData+fileName; if (extension!=".xml") return ComputeSpectralPeaks(ComputeSpectrum(ReadAudio(fullPath))); CLAM::SpectralPeakArray peaks; CLAM::XMLStorage::Restore(peaks,fullPath); return peaks; } void assertDescriptorExtractionInsideTolerance(const std::map & expected, CLAM::TData tolerance, CLAM::TData & (CLAM::SpectralPeakDescriptors::*getter)() const ) { std::stringstream log; bool success = true; mDescriptors->UpdateData(); CLAM::SpectralPeakArray peaks; std::map::const_iterator it; for (it = expected.begin(); it != expected.end(); it++) { peaks = helperGetData(it->first); // CLAM::XMLStorage::Dump(peaks, "Peaks", mPathToTestData + "/SpectralPeaks/" + it->first + "-Peaks.xml"); mDescriptors->SetpSpectralPeakArray(&peaks); mDescriptors->Compute(); if ( (std::isnan((mDescriptors->*getter)()) != std::isnan(it->second)) || (std::isinf((mDescriptors->*getter)()) != std::isinf(it->second)) || (mDescriptors->*getter)() > (*it).second + tolerance || (mDescriptors->*getter)() < (*it).second - tolerance ) { log << (*it).first << ": expected " << (*it).second << ", received " << (mDescriptors->*getter)() << std::endl; success = false; } } CPPUNIT_ASSERT_MESSAGE(std::string("Error margins surpassed:\n")+log.str() ,success); } private: void testDataAttachment_whenLogDataFails() { CLAM::SpectralPeakArray peaks; peaks = helperGetData("bell_A3.wav-Peaks.xml"); peaks.SetScale(CLAM::EScale::eLog); try { mDescriptors->SetpSpectralPeakArray(&peaks); CPPUNIT_FAIL("Should have thrown an exception"); } catch (const CLAM::ErrAssertionFailed & e) { std::string msg = e.what(); CPPUNIT_ASSERT_EQUAL(std::string("Spectral Peak Descriptors require a linear magnitude SpectralPeakArray"), std::string(e.what())); } } void testConstructionDataAttachment_whenLogDataFails() { CLAM::SpectralPeakArray peaks; peaks = helperGetData("bell_A3.wav-Peaks.xml"); peaks.SetScale(CLAM::EScale::eLog); try { CLAM::SpectralPeakDescriptors peakDescriptors(&peaks); CPPUNIT_FAIL("Should have thrown an exception"); } catch (const CLAM::ErrAssertionFailed & e) { std::string msg = e.what(); CPPUNIT_ASSERT_EQUAL(std::string("Spectral Peak Descriptors require a linear magnitude SpectralPeakArray"), std::string(e.what())); } } void testMagnitudeMean() { CLAM::TData tolerance = 0.0001; // Due to numerical inaccuracies std::map data; data["Serie1To5-Peaks.xml"] = 3; data["No-Peaks.xml"] = 0; data["Single-Peaks.xml"] = 4; data["5FlatSloped-Peaks.xml"] = 5; data["bell_A3.wav-Peaks.xml"] = 4.69634; data["5LinearSloped-Peaks.xml"] = 6; mDescriptors->AddMagnitudeMean(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralPeakDescriptors::GetMagnitudeMean); } void testHarmonicCentroid() { CLAM::TData tolerance = 0.01; // Due to numerical inaccuracies std::map data; data["Serie1To5-Peaks.xml"] = 366.6667; data["No-Peaks.xml"] = 0; data["Single-Peaks.xml"] = 1500; data["5FlatSloped-Peaks.xml"] = 940; data["bell_A3.wav-Peaks.xml"] = 2463.38; data["5LinearSloped-Peaks.xml"] = 580; mDescriptors->AddHarmonicCentroid(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralPeakDescriptors::GetHarmonicCentroid); } void testHarmonicDeviation() { CLAM::TData tolerance = 0.0001; // Due to numerical inaccuracies std::map data; data["Serie1To5-Peaks.xml"] = 0.1067; data["No-Peaks.xml"] = 0; data["Single-Peaks.xml"] = 0; data["5FlatSloped-Peaks.xml"] = 0; data["bell_A3.wav-Peaks.xml"] = 2.02832; data["5LinearSloped-Peaks.xml"] = 0.061894; data["Serie5To1-Peaks.xml"] = 0.1067; mDescriptors->AddHarmonicDeviation (); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralPeakDescriptors::GetHarmonicDeviation); } void testFirstTristimulus() { CLAM::TData tolerance = 0.0001; // Due to numerical inaccuracies std::map data; data["Serie1To5-Peaks.xml"] = 0.0181818; data["No-Peaks.xml"] = 0; data["Single-Peaks.xml"] = 1; data["5FlatSloped-Peaks.xml"] = 0.2; data["bell_A3.wav-Peaks.xml"] = 4.5164e-005; data["5LinearSloped-Peaks.xml"] = 0.4545; mDescriptors->AddFirstTristimulus(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralPeakDescriptors::GetFirstTristimulus); } void testSecondTristimulus() { CLAM::TData tolerance = 0.0001; // Due to numerical inaccuracies std::map data; data["Serie1To5-Peaks.xml"] = 0.527273; data["No-Peaks.xml"] = 0; data["Single-Peaks.xml"] = 0; data["5FlatSloped-Peaks.xml"] = 0.6; data["bell_A3.wav-Peaks.xml"] = 0.00486879; data["5LinearSloped-Peaks.xml"] = 0.5273; mDescriptors->AddSecondTristimulus(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralPeakDescriptors::GetSecondTristimulus); } void testThirdTristimulus() { CLAM::TData tolerance = 0.0001; // Due to numerical inaccuracies std::map data; data["Serie1To5-Peaks.xml"] = 0.454545; data["No-Peaks.xml"] = 0; data["Single-Peaks.xml"] =0; data["5FlatSloped-Peaks.xml"] = 0.2; data["bell_A3.wav-Peaks.xml"] = 0.995086; data["5LinearSloped-Peaks.xml"] = 0.0182; mDescriptors->AddThirdTristimulus(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralPeakDescriptors::GetThirdTristimulus); } void testOddHarmonics() { CLAM::TData tolerance = 0.0001; // Due to numerical inaccuracies std::map data; data["Serie1To5-Peaks.xml"] = 0.618182; data["No-Peaks.xml"] = 0; data["Single-Peaks.xml"] =0; data["5FlatSloped-Peaks.xml"] = 0.4; data["bell_A3.wav-Peaks.xml"] =0.365391 ; data["5LinearSloped-Peaks.xml"] = 0.1818; mDescriptors->AddOddHarmonics(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralPeakDescriptors::GetOddHarmonics); } void testEvenHarmonics() { CLAM::TData tolerance = 0.0001; // Due to numerical inaccuracies std::map data; data["Serie1To5-Peaks.xml"] = 0.363636; data["No-Peaks.xml"] = 0; data["Single-Peaks.xml"] =0; data["5FlatSloped-Peaks.xml"] = 0.4; data["bell_A3.wav-Peaks.xml"] = 0.634564; data["5LinearSloped-Peaks.xml"] = 0.3636; mDescriptors->AddEvenHarmonics(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralPeakDescriptors::GetEvenHarmonics); } void testOddToEvenRatio() { CLAM::TData tolerance = 0.0001; // Due to numerical inaccuracies std::map data; data["Serie1To5-Peaks.xml"] = 0.6296; data["No-Peaks.xml"] = 0.5; data["Single-Peaks.xml"] =0.5; data["5FlatSloped-Peaks.xml"] = 0.5; data["bell_A3.wav-Peaks.xml"] = 0.365407; data["5LinearSloped-Peaks.xml"] = 0.3333; mDescriptors->AddOddToEvenRatio(); assertDescriptorExtractionInsideTolerance(data, tolerance, &CLAM::SpectralPeakDescriptors::GetOddToEvenRatio); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/NonComponentData/0000755000000000000000000000000011344231440017252 5ustar rootrootclam-1.4.0/test/UnitTests/NonComponentData/FlagsTest.cxx0000644000000000000000000002373711113062376021712 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ // TODO: Symbolic operation #include "Flags.hxx" // CLAM #include #include #include "XMLTestHelper.hxx" using namespace CLAM; ///////////////////////////////////////////////////////////////////// // Test Class ///////////////////////////////////////////////////////////////////// namespace CLAMTest { class FlagsTest; CPPUNIT_TEST_SUITE_REGISTRATION( FlagsTest ); class MyFlags : public Flags<5> { // Construction/Destruction public: static tFlagValue sFlagValues[]; static tValue sDefault; virtual Component * Species() const { return new MyFlags(); } typedef enum { eFlag0=0, eFlag1=1, eFlag2=2, eFlag3=3, eFlag4=4 } tFlag; MyFlags () : Flags<5>(sFlagValues), flag0(operator[](eFlag0)), flag1(operator[](eFlag1)), flag2(operator[](eFlag2)), flag3(operator[](eFlag3)), flag4(operator[](eFlag4)) { flag4=true; }; MyFlags (const MyFlags& someFlags) : Flags<5>(sFlagValues,someFlags), flag0(operator[](eFlag0)), flag1(operator[](eFlag1)), flag2(operator[](eFlag2)), flag3(operator[](eFlag3)), flag4(operator[](eFlag4)) {}; MyFlags(int i) : Flags<5>(sFlagValues, i), flag0(operator[](eFlag0)), flag1(operator[](eFlag1)), flag2(operator[](eFlag2)), flag3(operator[](eFlag3)), flag4(operator[](eFlag4)) {}; reference flag0; reference flag1; reference flag2; reference flag3; reference flag4; bool Matches(bool f0, bool f1, bool f2, bool f3, bool f4) { // This check is done in this weird way in order not to // mask type errors with phantom implicit conversions bool ok = FullfilsInvariant(); // ok &= (f2? flag2: !flag2); if (f0!=operator[](0)) ok=ReportNotMatch(0,f0,operator[](0)); if (f1!=operator[](1)) ok=ReportNotMatch(1,f1,operator[](1)); if (f2!=operator[](2)) ok=ReportNotMatch(2,f2,operator[](2)); if (f3!=operator[](3)) ok=ReportNotMatch(3,f3,operator[](3)); if (f4!=operator[](4)) ok=ReportNotMatch(4,f4,operator[](4)); return ok; } bool ReportNotMatch(const int place, const bool expected, const bool found) { const bool verbose = true; if (verbose) { std::cout << "Flag at positon " << place << " expected: " << expected << " and found: " << found << std::endl; } return false; } bool FullfilsInvariant() { bool ok = true; if (flag0!=operator[](0)) ok=ReportReferencesDoNotMatch(0,flag0,operator[](0)); if (flag1!=operator[](1)) ok=ReportReferencesDoNotMatch(1,flag1,operator[](1)); if (flag2!=operator[](2)) ok=ReportReferencesDoNotMatch(2,flag2,operator[](2)); if (flag3!=operator[](3)) ok=ReportReferencesDoNotMatch(3,flag3,operator[](3)); if (flag4!=operator[](4)) ok=ReportReferencesDoNotMatch(4,flag4,operator[](4)); return ok; } bool ReportReferencesDoNotMatch(const int place, const bool ref, const bool op) { const bool verbose = true; if (verbose) { std::cout << "Internal bit reference inconsistency" << " at positon " << place << " by reference: " << ref << " by [] operator: " << op << " " << std::endl; } return false; } static void TestInputOutput (); static void TestOperations (); }; Flags<5>::tFlagValue MyFlags::sFlagValues[] = { {MyFlags::eFlag0, "flag0"}, {MyFlags::eFlag1, "flag1"}, {MyFlags::eFlag2, "flag2"}, {MyFlags::eFlag3, "flag3"}, {MyFlags::eFlag4, "flag4"}, {0,NULL} }; /** * @todo Symbolic operation * @todo Remove console output */ class FlagsTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE (CLAMTest::FlagsTest); CPPUNIT_TEST (testDefaultConstructor); CPPUNIT_TEST (testValueConstructor); CPPUNIT_TEST (testEqualOperator_withEquivalentFlags); CPPUNIT_TEST (testEqualOperator_withDifferentFlags); CPPUNIT_TEST (testCopyConstructor_AdoptValuesValues); CPPUNIT_TEST (testCopyConstructor_DoesNotCreateAliasingOnWriteCopy); CPPUNIT_TEST (testCopyConstructor_DoesNotCreateAliasingOnWriteOriginal); CPPUNIT_TEST (testOrAssignmentOperator); CPPUNIT_TEST (testReset); CPPUNIT_TEST (testDirectFlagSetting_withTrue_whenSet); CPPUNIT_TEST (testDirectFlagSetting_withTrue_whenNotSet); CPPUNIT_TEST (testDirectFlagSetting_withFalse_whenSet); CPPUNIT_TEST (testDirectFlagSetting_withFalse_whenNotSet); CPPUNIT_TEST (testFlip_whenSet); CPPUNIT_TEST (testFlip_whenNotSet); CPPUNIT_TEST (testExtraction_withCorrectInputs); CPPUNIT_TEST (testExtraction_withIncorrectInputs); CPPUNIT_TEST (testExtraction_withResetFlags); CPPUNIT_TEST (testReloadingXML); // CPPUNIT_TEST (testStringConstructor); // CPPUNIT_TEST (testSetValue); // CPPUNIT_TEST (testSetValue_WithString); // CPPUNIT_TEST (testSetValueSafely_WithIllegalString); // CPPUNIT_TEST (testSetValueSafely_WithIllegalValue); CPPUNIT_TEST_SUITE_END(); private: void testDefaultConstructor() { MyFlags defaultConstructedFlags; CPPUNIT_ASSERT_MESSAGE("All but Flag4 must be off by default", defaultConstructedFlags.Matches(0,0,0,0,1)); } void testValueConstructor() { MyFlags flags1and2=3; CPPUNIT_ASSERT_MESSAGE("Only Flags0 and Flags1 must be on", flags1and2.Matches(1,1,0,0,0)); } void testEqualOperator_withEquivalentFlags() { MyFlags flags1and2=3; MyFlags flags1and2sibbling=3; CPPUNIT_ASSERT_EQUAL(true, flags1and2 == flags1and2sibbling); } void testEqualOperator_withDifferentFlags() { MyFlags flags1and2=3; MyFlags onlyFlag4; CPPUNIT_ASSERT_EQUAL(false, flags1and2 == onlyFlag4); } void testCopyConstructor_AdoptValuesValues() { MyFlags original=7; MyFlags copied(original); CPPUNIT_ASSERT_EQUAL(original,copied); } void testCopyConstructor_DoesNotCreateAliasingOnWriteCopy() { MyFlags original=7; MyFlags copied(original); MyFlags expectedOriginal=7; MyFlags expectedCopied=6; copied.flag0=false; CPPUNIT_ASSERT_EQUAL(expectedOriginal, original); CPPUNIT_ASSERT_EQUAL(expectedCopied, copied); } void testCopyConstructor_DoesNotCreateAliasingOnWriteOriginal() { MyFlags original=7; MyFlags copied(original); MyFlags expectedOriginal=6; MyFlags expectedCopied=7; original.flag0=false; CPPUNIT_ASSERT_EQUAL(expectedOriginal, original); CPPUNIT_ASSERT_EQUAL(expectedCopied, copied); } void testOrAssignmentOperator() { MyFlags flags4=16; MyFlags toBeOred=3; MyFlags expected= (3|16); toBeOred |= flags4; CPPUNIT_ASSERT_EQUAL(expected, toBeOred); } void testReset() { MyFlags resetted=5; MyFlags expected=0; resetted.reset(); CPPUNIT_ASSERT_EQUAL(expected, resetted); } void testDirectFlagSetting_withTrue_whenNotSet() { MyFlags toBeSet=5; MyFlags expected=(5|16); toBeSet.flag4=true; CPPUNIT_ASSERT_EQUAL(expected, toBeSet); } void testDirectFlagSetting_withTrue_whenSet() { MyFlags toBeSet=5; MyFlags expected=5; toBeSet.flag2=true; CPPUNIT_ASSERT_EQUAL(expected, toBeSet); } void testDirectFlagSetting_withFalse_whenNotSet() { MyFlags toBeSet=5; MyFlags expected=5; toBeSet.flag3=false; CPPUNIT_ASSERT_EQUAL(expected, toBeSet); } void testDirectFlagSetting_withFalse_whenSet() { MyFlags toBeSet=5; MyFlags expected=5 & ~1; toBeSet.flag0=false; CPPUNIT_ASSERT_EQUAL(expected, toBeSet); } void testFlip_whenSet() { MyFlags toBeFlipped=5; MyFlags expected=5 & ~4; toBeFlipped.flag2.flip(); CPPUNIT_ASSERT_EQUAL(expected, toBeFlipped); } void testFlip_whenNotSet() { MyFlags toBeFlipped=5; MyFlags expected=5 | 16; toBeFlipped.flag4.flip(); CPPUNIT_ASSERT_EQUAL(expected, toBeFlipped); } void testReloadingXML() { MyFlags A=5; MyFlags B=21; MyFlags C=0; CPPUNIT_ASSERT_MESSAGE( "Failed: The loaded version of A stores differently than the original A", XMLInputOutputMatches(A,"FlagA.xml")); CPPUNIT_ASSERT_MESSAGE( "Failed: The loaded version of B stores differently than the original B", XMLInputOutputMatches(B,"FlagB.xml")); CPPUNIT_ASSERT_MESSAGE( "Failed: The loaded version of C stores differently than the original C", XMLInputOutputMatches(C,"FlagC.xml")); } void testExtraction_withIncorrectInputs() { const char * inputstring[] = { "{flag0 fla2 flag3 }", "{fla0 flag2 flag3 }", NULL }; for (int i=0; inputstring[i]; i++) { std::stringstream is(inputstring[i]); MyFlags flag=16; MyFlags expected=16; try { is >> flag; CPPUNIT_FAIL("Incorrect input did not fail"); } catch(...) { CPPUNIT_ASSERT_EQUAL(expected, flag); } } } void testExtraction_withCorrectInputs() { const char * inputstring[] = { "{flag0 flag2 flag3}", "{ flag0 flag2 flag3 }", " { flag0 flag2 flag3 } ", " { flag0 flag2 flag3 } ", NULL }; MyFlags expected = 13; for (int i=0; inputstring[i]; i++) { std::stringstream is(inputstring[i]); MyFlags read; is >> read; CPPUNIT_ASSERT_EQUAL(expected, read); } } void testExtraction_withResetFlags() { const char * inputstring[] = { "{}", " { } ", " { } ", NULL }; MyFlags expected = 0; for (int i=0; inputstring[i]; i++) { std::stringstream is(inputstring[i]); MyFlags read; is >> read; CPPUNIT_ASSERT_EQUAL(expected, read); } } }; } clam-1.4.0/test/UnitTests/NonComponentData/TextTest.cxx0000644000000000000000000001012611122320603021554 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "Text.hxx" // CLAM #include "DynamicType.hxx" // CLAM #include "XMLStorage.hxx" // CLAM #include "XMLTestHelper.hxx" #include using namespace CLAM; ///////////////////////////////////////////////////////////////////// // Test Class ///////////////////////////////////////////////////////////////////// namespace CLAMTest { class TextTest; CPPUNIT_TEST_SUITE_REGISTRATION( TextTest ); class TextTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE (CLAMTest::TextTest); CPPUNIT_TEST (testDefaultConstructor); CPPUNIT_TEST (testStringComparation_whenEqual); CPPUNIT_TEST (testStringComparation_whenDiffers); CPPUNIT_TEST (testInitializationFromCharPointer); CPPUNIT_TEST (testStreamExtraction_withSpaces); CPPUNIT_TEST (testStreamExtraction_withTabs); CPPUNIT_TEST (testStreamExtraction_clearsPreviousContent); CPPUNIT_TEST (testXml_output); CPPUNIT_TEST (testXml_inputOutputAreIdempotent); CPPUNIT_TEST_SUITE_END(); private: class TextContainerComponent : public CLAM::DynamicType { public: DYNAMIC_TYPE(TextContainerComponent, 1); DYN_ATTRIBUTE(0, public, CLAM::Text, Text); }; private: void testDefaultConstructor() { CLAM::Text text; CPPUNIT_ASSERT_EQUAL(CLAM::Text(""), text); } void testStringComparation_whenEqual() { CLAM::Text text("Hola"); std::string str("Hola"); bool result = (text==str); CPPUNIT_ASSERT_EQUAL(true, result); } void testStringComparation_whenDiffers() { CLAM::Text text("Hola"); std::string str("Adios"); bool result = (text==str); CPPUNIT_ASSERT_EQUAL(false, result); } void testInitializationFromCharPointer() { CLAM::Text text = "Hola"; std::string & str = text; CPPUNIT_ASSERT_EQUAL(std::string("Hola"), str); } void testStreamExtraction_withSpaces() { std::string toberead("Hola tu"); std::istringstream myistream (toberead); CLAM::Text extracted; myistream >> extracted; CLAM::Text expected("Hola tu"); CPPUNIT_ASSERT_EQUAL(expected, extracted); } void testStreamExtraction_withTabs() { std::string toberead("Hola\t tu"); std::istringstream myistream (toberead); CLAM::Text extracted; myistream >> extracted; CLAM::Text expected("Hola\t tu"); CPPUNIT_ASSERT_EQUAL(expected, extracted); } void testStreamExtraction_clearsPreviousContent() { std::string toberead("Hola"); std::istringstream myistream (toberead); CLAM::Text extracted("Previous content"); myistream >> extracted; CLAM::Text expected("Hola"); CPPUNIT_ASSERT_EQUAL(expected, extracted); } void testXml_inputOutputAreIdempotent() { TextContainerComponent component; component.AddText(); component.UpdateData(); component.SetText("La cadena esperada"); bool match = XMLInputOutputMatches(component,__FILE__"TextContainer.xml"); CLAM_ASSERT(match, "Text Store/Load mismatch"); } void testXml_output() { TextContainerComponent component; component.AddText(); component.UpdateData(); component.SetText("La cadena esperada"); std::stringstream stream; XMLStorage storage; storage.Dump(component, "object", stream, false); CLAMTEST_ASSERT_XML_EQUAL( "La cadena esperada\n", stream.str()); } }; } clam-1.4.0/test/UnitTests/NonComponentData/PointTest.cxx0000644000000000000000000000606610610720021021730 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "Point.hxx" // CLAM namespace CLAMTest { class PointTest; CPPUNIT_TEST_SUITE_REGISTRATION( PointTest ); class PointTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( PointTest ); CPPUNIT_TEST( testConstructor_TakesValues ); CPPUNIT_TEST( testDefaultConstructor_InitAsZero ); CPPUNIT_TEST( testSetY ); CPPUNIT_TEST( testSetX ); CPPUNIT_TEST( testInequality_WithDifferentValues ); CPPUNIT_TEST( testStreamInsertion ); CPPUNIT_TEST( testStreamExtraction ); CPPUNIT_TEST( testStreamExtraction_WithSpacesToBeIgnored ); CPPUNIT_TEST( testStreamExtraction_WithADifferentStartToken ); CPPUNIT_TEST( testStreamExtraction_WithADifferentEndToken ); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: void testConstructor_TakesValues() { CLAM::Point aPoint(3.0, 2.0); CPPUNIT_ASSERT_EQUAL( CLAM::TData(3.0), aPoint.GetX()); CPPUNIT_ASSERT_EQUAL( CLAM::TData(2.0), aPoint.GetY()); } void testDefaultConstructor_InitAsZero() { CLAM::Point zeroPoint(0.0, 0.0); CLAM::Point aDefaultConstructedPoint; CPPUNIT_ASSERT_EQUAL(aDefaultConstructedPoint, zeroPoint); } void testInequality_WithDifferentValues() { CLAM::Point pureXUnitPoint(1.0, 0.0); CLAM::Point pureYUnitPoint(0.0, 1.0); CPPUNIT_ASSERT(pureYUnitPoint != pureXUnitPoint); } void testSetY() { CLAM::Point aPoint(3.0, 2.0); aPoint.SetY(4.3); CPPUNIT_ASSERT_EQUAL(CLAM::Point(3.0,4.3), aPoint); } void testSetX() { CLAM::Point aPoint(3.0, 2.0); aPoint.SetX(4.3); CPPUNIT_ASSERT_EQUAL(CLAM::Point(4.3,2.0), aPoint); } void testStreamInsertion() { std::stringstream s; CLAM::Point point(1.453,3.454); std::string expectedString("{1.453 3.454}"); s << point << std::flush; CPPUNIT_ASSERT_EQUAL(expectedString, s.str()); } void testStreamExtraction() { CLAM::Point toBeModified(1,3); std::string inputString("{5.3 7.3}"); CLAM::Point expected(5.3, 7.3); std::stringstream s(inputString); s >> toBeModified; CPPUNIT_ASSERT_EQUAL(expected, toBeModified); } void testStreamExtraction_WithSpacesToBeIgnored() { CLAM::Point toBeModified(1,3); std::string inputString(" \n { \n 5.3 \n 7.3 \t } "); CLAM::Point expected(5.3, 7.3); std::stringstream s(inputString); s >> toBeModified; CPPUNIT_ASSERT_EQUAL(expected, toBeModified); } void testStreamExtraction_WithADifferentStartToken() { CLAM::Point toBeModified(1.3,3.2); CLAM::Point expected (1.3,3.2); std::string inputString("a{5.3 7.3}"); std::stringstream ss(inputString); ss >> toBeModified; CPPUNIT_ASSERT_EQUAL(expected, toBeModified); } void testStreamExtraction_WithADifferentEndToken() { CLAM::Point toBeModified(1.3,3.2); CLAM::Point expected (1.3,3.2); std::string inputString("{5.3 7.3a a"); std::stringstream ss(inputString); ss >> toBeModified; CPPUNIT_ASSERT_EQUAL(expected, toBeModified); } }; } // namespace CLAMTes clam-1.4.0/test/UnitTests/NonComponentData/ComplexTest.cxx0000644000000000000000000000631610610720021022244 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "Complex.hxx" // CLAM namespace CLAMTest { class ComplexTest; CPPUNIT_TEST_SUITE_REGISTRATION( ComplexTest ); class ComplexTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ComplexTest ); CPPUNIT_TEST( testConstructor_TakesValues ); CPPUNIT_TEST( testDefaultConstructor_InitAsZero ); CPPUNIT_TEST( testSetImag ); CPPUNIT_TEST( testSetReal ); CPPUNIT_TEST( testInequality_WithDifferentValues ); CPPUNIT_TEST( testStreamInsertion ); CPPUNIT_TEST( testStreamExtraction ); CPPUNIT_TEST( testStreamExtraction_WithSpacesToBeIgnored ); CPPUNIT_TEST( testStreamExtraction_WithADifferentStartToken ); CPPUNIT_TEST( testStreamExtraction_WithADifferentEndToken ); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: void testConstructor_TakesValues() { CLAM::Complex aComplex(3.0, 2.0); CPPUNIT_ASSERT_EQUAL( CLAM::TData(3.0), aComplex.Real()); CPPUNIT_ASSERT_EQUAL( CLAM::TData(2.0), aComplex.Imag()); } void testDefaultConstructor_InitAsZero() { CLAM::Complex zeroComplex(0.0, 0.0); CLAM::Complex aDefaultConstructedComplex; CPPUNIT_ASSERT_EQUAL(aDefaultConstructedComplex, zeroComplex); } void testInequality_WithDifferentValues() { CLAM::Complex pureRealUnitComplex(1.0, 0.0); CLAM::Complex pureImagUnitComplex(0.0, 1.0); CPPUNIT_ASSERT(pureImagUnitComplex != pureRealUnitComplex); } void testSetImag() { CLAM::Complex aComplex(3.0, 2.0); aComplex.SetImag(4.3); CPPUNIT_ASSERT_EQUAL(CLAM::Complex(3.0,4.3), aComplex); } void testSetReal() { CLAM::Complex aComplex(3.0, 2.0); aComplex.SetReal(4.3); CPPUNIT_ASSERT_EQUAL(CLAM::Complex(4.3,2.0), aComplex); } void testStreamInsertion() { std::stringstream s; CLAM::Complex complex(1.453,3.454); std::string expectedString("{1.453 3.454i}"); s << complex << std::flush; CPPUNIT_ASSERT_EQUAL(expectedString, s.str()); } void testStreamExtraction() { CLAM::Complex toBeModified(1,3); std::string inputString("{5.4 7.4i}"); CLAM::Complex expected( CLAM::TData(5.4), CLAM::TData(7.4) ); std::stringstream ss(inputString); ss >> toBeModified; CPPUNIT_ASSERT_EQUAL(expected, toBeModified); } void testStreamExtraction_WithSpacesToBeIgnored() { CLAM::Complex toBeModified(1,3); std::string inputString(" \n { \n 5.3 \n 7.3 i \t } "); CLAM::Complex expected(5.3, 7.3); std::stringstream ss(inputString); ss >> toBeModified; CPPUNIT_ASSERT_EQUAL(expected, toBeModified); } void testStreamExtraction_WithADifferentStartToken() { CLAM::Complex toBeModified(1.3,3.2); CLAM::Complex expected (1.3,3.2); std::string inputString("a{5.3 7.3i}"); std::stringstream ss(inputString); ss >> toBeModified; CPPUNIT_ASSERT_EQUAL(expected, toBeModified); } void testStreamExtraction_WithADifferentEndToken() { CLAM::Complex toBeModified(1.3,3.2); CLAM::Complex expected (1.3,3.2); std::string inputString("{5.3 7.3ia a"); std::stringstream ss(inputString); ss >> toBeModified; CPPUNIT_ASSERT_EQUAL(expected, toBeModified); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/NonComponentData/PolarTest.cxx0000644000000000000000000000611510610720021021707 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "Polar.hxx" // CLAM namespace CLAMTest { class PolarTest; CPPUNIT_TEST_SUITE_REGISTRATION( PolarTest ); class PolarTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( PolarTest ); CPPUNIT_TEST( testConstructor_TakesValues ); CPPUNIT_TEST( testDefaultConstructor_InitAsZero ); CPPUNIT_TEST( testSetAng ); CPPUNIT_TEST( testSetMag ); CPPUNIT_TEST( testInequality_WithDifferentValues ); CPPUNIT_TEST( testStreamInsertion ); CPPUNIT_TEST( testStreamExtraction ); CPPUNIT_TEST( testStreamExtraction_WithSpacesToBeIgnored ); CPPUNIT_TEST( testStreamExtraction_WithADifferentStartToken ); CPPUNIT_TEST( testStreamExtraction_WithADifferentEndToken ); CPPUNIT_TEST_SUITE_END(); public: /// Common initialization, executed before each test method void setUp() { } /// Common clean up, executed after each test method void tearDown() { } private: void testConstructor_TakesValues() { CLAM::Polar aPolar(3.0, 2.0); CPPUNIT_ASSERT_EQUAL( CLAM::TData(3.0), aPolar.Mag() ); CPPUNIT_ASSERT_EQUAL( CLAM::TData(2.0), aPolar.Ang() ); } void testDefaultConstructor_InitAsZero() { CLAM::Polar zeroPolar(0.0, 0.0); CLAM::Polar aDefaultConstructedPolar; CPPUNIT_ASSERT_EQUAL(aDefaultConstructedPolar, zeroPolar); } void testInequality_WithDifferentValues() { CLAM::Polar pureMagUnitPolar(1.0, 0.0); CLAM::Polar pureAngUnitPolar(0.0, 1.0); CPPUNIT_ASSERT(pureAngUnitPolar != pureMagUnitPolar); } void testSetAng() { CLAM::Polar aPolar(3.0, 2.0); aPolar.SetAng(4.3); CPPUNIT_ASSERT_EQUAL(CLAM::Polar(3.0,4.3), aPolar); } void testSetMag() { CLAM::Polar aPolar(3.0, 2.0); aPolar.SetMag(4.3); CPPUNIT_ASSERT_EQUAL(CLAM::Polar(4.3,2.0), aPolar); } void testStreamInsertion() { std::stringstream s; CLAM::Polar polar(1.453,3.454); std::string expectedString("{1.453 3.454}"); s << polar << std::flush; CPPUNIT_ASSERT_EQUAL(expectedString, s.str()); } void testStreamExtraction() { CLAM::Polar toBeModified(1,3); std::string inputString("{5.3 7.3}"); CLAM::Polar expected(5.3, 7.3); std::stringstream ss(inputString); ss >> toBeModified; CPPUNIT_ASSERT_EQUAL(expected, toBeModified); } void testStreamExtraction_WithSpacesToBeIgnored() { CLAM::Polar toBeModified(1,3); std::string inputString(" \n { \n 5.3 \n 7.3 \t } "); CLAM::Polar expected(5.3, 7.3); std::stringstream ss(inputString); ss >> toBeModified; CPPUNIT_ASSERT_EQUAL(expected, toBeModified); } void testStreamExtraction_WithADifferentStartToken() { CLAM::Polar toBeModified(1.3,3.2); CLAM::Polar expected (1.3,3.2); std::string inputString("a{5.3 7.3}"); std::stringstream ss(inputString); ss >> toBeModified; CPPUNIT_ASSERT_EQUAL(expected, toBeModified); } void testStreamExtraction_WithADifferentEndToken() { CLAM::Polar toBeModified(1.3,3.2); CLAM::Polar expected (1.3,3.2); std::string inputString("{5.3 7.3a a"); std::stringstream ss(inputString); ss >> toBeModified; CPPUNIT_ASSERT_EQUAL(expected, toBeModified); } }; } // namespace CLAMTes clam-1.4.0/test/UnitTests/NonComponentData/EnumTest.cxx0000644000000000000000000000675110442000724021550 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "Enum.hxx" // CLAM #include using namespace CLAM; ///////////////////////////////////////////////////////////////////// // Test Class ///////////////////////////////////////////////////////////////////// namespace CLAMTest { class EnumTest; CPPUNIT_TEST_SUITE_REGISTRATION( EnumTest ); class MyEnum : public Enum { public: static tValue sDefault; MyEnum() : Enum(EnumValues(), sDefault) {} MyEnum(tValue v) : Enum(EnumValues(), v) {}; MyEnum(std::string s) : Enum(EnumValues(), s) {}; virtual ~MyEnum() {}; Component * Species() const { return new MyEnum;}; typedef enum { zero=0, dos=2, cent=100 } tEnum; static Enum::tEnumValue * EnumValues() { static Enum::tEnumValue sEnumValues[] = { {MyEnum::zero,"zero"}, {MyEnum::dos,"dos"}, {MyEnum::cent,"cent"}, {0,NULL} }; return sEnumValues; } }; Enum::tValue MyEnum::sDefault = MyEnum::dos; class EnumTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE (CLAMTest::EnumTest); CPPUNIT_TEST (testDefaultConstructor); CPPUNIT_TEST (testValueConstructor); CPPUNIT_TEST (testStringConstructor); CPPUNIT_TEST (testSetValue); CPPUNIT_TEST (testSetValue_WithString); CPPUNIT_TEST (testSetValueSafely_WithIllegalString); CPPUNIT_TEST (testSetValueSafely_WithIllegalValue); CPPUNIT_TEST_SUITE_END(); private: void testDefaultConstructor() { MyEnum e; CPPUNIT_ASSERT_EQUAL_MESSAGE("Default constructor didn't get the expected value 'dos'", std::string("dos"),e.GetString()); } void testValueConstructor() { MyEnum e(MyEnum::cent); CLAM_ASSERT (e.GetString()=="cent", "Value constructor didn't get the expected value 'cent'"); } void testStringConstructor() { MyEnum e("cent"); CLAM_ASSERT (e.GetString()=="cent", "String constructor didn't get the expected value 'cent'"); } void testSetValue() { MyEnum e; e.SetValue(0); CLAM_ASSERT (e.GetString()=="zero", "SetValue(enum) didn't change the value to 'zero'"); } void testSetValue_WithString() { MyEnum e; e.SetValue("dos"); CLAM_ASSERT (e.GetString()=="dos", "SetValue(string) didn't change the value to 'dos'"); } void testSetValueSafely_WithIllegalString() { MyEnum e; try { e.SetValueSafely("dros"); CLAM_ASSERT (false, "Exception not thrown, when setting an illegal string symbol"); } catch (IllegalValue e) { // That's ok } } void testSetValueSafely_WithIllegalValue() { MyEnum e; try { e.SetValueSafely(4); CLAM_ASSERT (false, "Exception not thrown, when setting an illegal integer value"); } catch (IllegalValue e) { // That's ok } } }; } clam-1.4.0/test/UnitTests/ProcessingsTests/0000755000000000000000000000000011344231435017371 5ustar rootrootclam-1.4.0/test/UnitTests/ProcessingsTests/AudioMixerTest.cxx0000644000000000000000000000566511205565313023040 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "AudioMixer.hxx" // CLAM #include "Processing.hxx" // CLAM #include "Audio.hxx" // CLAM #include "OutControl.hxx" // CLAM namespace CLAMTest{ class AudioMixerTest; CPPUNIT_TEST_SUITE_REGISTRATION( AudioMixerTest ); class AudioMixerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( AudioMixerTest ); CPPUNIT_TEST( testDo_WhenControlsGivesEqualValue ); CPPUNIT_TEST( testDo_WhenControlsGivesDifferentValue ); CPPUNIT_TEST_SUITE_END(); //processing CLAM::FloatOutControl mOut1; CLAM::FloatOutControl mOut2; CLAM::AudioMixer mMixer; //data CLAM::Audio mInAudio1; CLAM::Audio mInAudio2; CLAM::Audio mOutAudio; const double mDelta; public: void setUp() { //add link to in controls of mixer mOut1.AddLink(mMixer.GetInControl("Input Gain_0")); mOut2.AddLink(mMixer.GetInControl("Input Gain_1")); mInAudio1.SetSize(1); mInAudio2.SetSize(1); mOutAudio.SetSize(1); CLAM::AudioMixerConfig mixerCfg; mixerCfg.SetFrameSize(1); mMixer.Configure(mixerCfg); mMixer.GetInPort("Input Audio_0").Attach(mInAudio1); mMixer.GetInPort("Input Audio_1").Attach(mInAudio2); mMixer.GetOutPort("Output Audio").Attach(mOutAudio); } public: AudioMixerTest() : mOut1("Sender left"), mOut2("Sender right"), mDelta(0.000001) { } private: void testDo_WhenControlsGivesEqualValue() { mInAudio1.GetBuffer()[0] = 1; mInAudio2.GetBuffer()[0] = 2; mMixer.Start(); const CLAM::TControlData val1(0.3f); const CLAM::TControlData val2(0.3f); mOut1.SendControl( val1 ); mOut2.SendControl( val2 ); mMixer.Do(); mMixer.Do(); CPPUNIT_ASSERT_EQUAL( CLAM::TControlData( val1 ), mMixer.GetInControl("Input Gain_0").GetLastValue()); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TData( (val1*1 + val2*2)/2 ) , mOutAudio.GetBuffer()[0], mDelta ); } void testDo_WhenControlsGivesDifferentValue() { mInAudio1.GetBuffer()[0] = 3; mInAudio2.GetBuffer()[0] = 2; mMixer.Start(); mOut1.SendControl(0.5f); mOut2.SendControl(0.6f); mMixer.Do(); mMixer.Do(); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TData(1.35) , mOutAudio.GetBuffer()[0], mDelta ); } }; } clam-1.4.0/test/UnitTests/ProcessingsTests/AutoPannerTest.cxx0000644000000000000000000001642411101735156023040 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "AutoPanner.hxx" // CLAM #include "InControl.hxx" // CLAM #include "OSDefines.hxx" // CLAM #include "Processing.hxx" // CLAM namespace CLAMTest { class AutoPannerTest; CPPUNIT_TEST_SUITE_REGISTRATION( AutoPannerTest ); class AutoPannerTest : public CppUnit::TestFixture, public CLAM::Processing { public: void setUp(){} void tearDown(){} private: CPPUNIT_TEST_SUITE( AutoPannerTest ); CPPUNIT_TEST( testDo_WhenFreqEqualSamplingRateAndNoPhase ); CPPUNIT_TEST( testDo_WhenFreqEqualSamplingRateWithPhase ); CPPUNIT_TEST( testDo_WhenFreqIsQuarterOfSamplingRate ); CPPUNIT_TEST( testDo_WhenFreqEqualSamplingRateAndFrameSizeIs10 ); CPPUNIT_TEST( testDo_WhenFreqIsQuarterOfSamplingRateAndPhaseAndFrameSizeIs7 ); CPPUNIT_TEST_SUITE_END(); // Testing pattern: Self Shunt // Processing interface: const char* GetClassName() const { return "for testing"; } bool Do() { return false; } const CLAM::ProcessingConfig& GetConfig() const { throw 0; } bool ConcreteConfigure( const CLAM::ProcessingConfig& ) { return false; } public: AutoPannerTest() : mReceiverLeft("Receiver Left",this), mReceiverRight("Receiver Right",this), mDelta(0.00001f) {} private: //fixture attributes CLAM::FloatInControl mReceiverLeft; CLAM::FloatInControl mReceiverRight; double mDelta; void testDo_WhenFreqEqualSamplingRateAndNoPhase() { CLAM::TData freq = 44100; CLAM::TData samplingRate = 44100; CLAM::TData phase = 0.0; int frameSize = 1; CLAM::AutoPanner controlSender; controlSender.GetOutControl("Left Control").AddLink(mReceiverLeft); controlSender.GetOutControl("Right Control").AddLink(mReceiverRight); CLAM::AutoPannerConfig cfg; cfg.SetFrequency( freq ); cfg.SetSamplingRate( samplingRate ); cfg.SetPhase( phase ); cfg.SetFrameSize( frameSize ); controlSender.Configure(cfg); controlSender.Start(); controlSender.Do(); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(0.0) , mReceiverLeft.GetLastValue(),mDelta); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(1.0) , mReceiverRight.GetLastValue(),mDelta); controlSender.Do(); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(0.0) , mReceiverLeft.GetLastValue(),mDelta); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(1.0) , mReceiverRight.GetLastValue(),mDelta); controlSender.Stop(); } void testDo_WhenFreqEqualSamplingRateWithPhase() { CLAM::TData freq = 44100; CLAM::TData samplingRate = 44100; CLAM::TData phase = CLAM::TData(M_PI/2); int frameSize = 1; CLAM::AutoPanner controlSender; controlSender.GetOutControl("Left Control").AddLink(mReceiverLeft); controlSender.GetOutControl("Right Control").AddLink(mReceiverRight); CLAM::AutoPannerConfig cfg; cfg.SetFrequency( freq ); cfg.SetSamplingRate( samplingRate ); cfg.SetPhase( phase ); cfg.SetFrameSize( frameSize ); controlSender.Configure(cfg); controlSender.Start(); controlSender.Do(); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(1.0) , mReceiverLeft.GetLastValue(),mDelta); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(0.0) , mReceiverRight.GetLastValue(),mDelta); controlSender.Do(); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(1.0) , mReceiverLeft.GetLastValue(),mDelta); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(0.0) , mReceiverRight.GetLastValue(),mDelta); controlSender.Stop(); } void testDo_WhenFreqIsQuarterOfSamplingRate() { CLAM::TData samplingRate = 44100; CLAM::TData freq = samplingRate/4; CLAM::TData phase = 0; int frameSize = 1; CLAM::AutoPanner controlSender; controlSender.GetOutControl("Left Control").AddLink(mReceiverLeft); controlSender.GetOutControl("Right Control").AddLink(mReceiverRight); CLAM::AutoPannerConfig cfg; cfg.SetFrequency( freq ); cfg.SetSamplingRate( samplingRate ); cfg.SetPhase( phase ); cfg.SetFrameSize( frameSize ); controlSender.Configure(cfg); controlSender.Start(); controlSender.Do(); //first Do gives the initial state, already tested controlSender.Do(); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(1.0) , mReceiverLeft.GetLastValue(),mDelta); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(0.0) , mReceiverRight.GetLastValue(),mDelta); controlSender.Stop(); } void testDo_WhenFreqEqualSamplingRateAndFrameSizeIs10() { CLAM::TData freq = 44100; CLAM::TData samplingRate = 44100; CLAM::TData phase = 0.0; int frameSize = 10; CLAM::AutoPanner controlSender; controlSender.GetOutControl("Left Control").AddLink(mReceiverLeft); controlSender.GetOutControl("Right Control").AddLink(mReceiverRight); CLAM::AutoPannerConfig cfg; cfg.SetFrequency( freq ); cfg.SetSamplingRate( samplingRate ); cfg.SetPhase( phase ); cfg.SetFrameSize( frameSize ); controlSender.Configure(cfg); controlSender.Start(); controlSender.Do(); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(0.0) , mReceiverLeft.GetLastValue(),mDelta); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(1.0) , mReceiverRight.GetLastValue(),mDelta); controlSender.Do(); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(0.0) , mReceiverLeft.GetLastValue(),mDelta); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(1.0) , mReceiverRight.GetLastValue(),mDelta); controlSender.Stop(); } void testDo_WhenFreqIsQuarterOfSamplingRateAndPhaseAndFrameSizeIs7() { CLAM::TData samplingRate = 44100; CLAM::TData freq = samplingRate/4; CLAM::TData phase = CLAM::TData(M_PI); int frameSize = 7; CLAM::AutoPanner controlSender; controlSender.GetOutControl("Left Control").AddLink(mReceiverLeft); controlSender.GetOutControl("Right Control").AddLink(mReceiverRight); CLAM::AutoPannerConfig cfg; cfg.SetFrequency( freq ); cfg.SetSamplingRate( samplingRate ); cfg.SetPhase( phase ); cfg.SetFrameSize( frameSize ); controlSender.Configure(cfg); controlSender.Start(); controlSender.Do(); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(0.0) , mReceiverLeft.GetLastValue(),mDelta); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(1.0) , mReceiverRight.GetLastValue(),mDelta); controlSender.Do(); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(1.0) , mReceiverLeft.GetLastValue(),mDelta); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(0.0) , mReceiverRight.GetLastValue(),mDelta); controlSender.Do(); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(0.0) , mReceiverLeft.GetLastValue(),mDelta); CPPUNIT_ASSERT_DOUBLES_EQUAL( CLAM::TControlData(1.0) , mReceiverRight.GetLastValue(),mDelta); controlSender.Stop(); } }; } //namespace CLAMTest clam-1.4.0/test/UnitTests/VisualizationTests/0000755000000000000000000000000011344231437017735 5ustar rootrootclam-1.4.0/test/UnitTests/VisualizationTests/UnsizedSegmentationTest.cxx0000644000000000000000000000770011032460057025320 0ustar rootroot#include #include "cppUnitHelper.hxx" // necessary for the custom assert #include "UnsizedSegmentation.hxx" #include "XMLTestHelper.hxx" #include using CLAM::UnsizedSegmentation; using CLAM::XmlStorage; namespace CLAMTest { class UnsizedSegmentationTest; CPPUNIT_TEST_SUITE_REGISTRATION( UnsizedSegmentationTest ); class UnsizedSegmentationTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( UnsizedSegmentationTest ); CPPUNIT_TEST( testStoreOn); CPPUNIT_TEST( testtakeArray); CPPUNIT_TEST( testLoadFromWithoutMaxPos); CPPUNIT_TEST( testLoadFromWithMaxPos); CPPUNIT_TEST(testStoreOn_withinAnArray); CPPUNIT_TEST(testLoadFromWithoutMaxPos_withinAnArray); CPPUNIT_TEST(testLoadFromWithMaxPos_withinAnArray); CPPUNIT_TEST_SUITE_END(); public: void testStoreOn() { const TData onsets[]={90, 100, 110, 120}; UnsizedSegmentation segmentation(200, onsets, onsets+4); std::ostringstream stream; XmlStorage::Dump(segmentation, "Segmentation", stream); CLAMTEST_ASSERT_XML_EQUAL( "90 100 110 120" , stream.str()); } void testtakeArray() { const TData bounds[]={90, 100, 110, 120}; UnsizedSegmentation segmentation(200); segmentation.takeArray(bounds, bounds+4); CPPUNIT_ASSERT_EQUAL(std::string("(90,90) (100,100) (110,110) (120,120) "), segmentation.boundsAsString()); } void testLoadFromWithoutMaxPos() { UnsizedSegmentation segmentation(200); std::istringstream stream("90 100 110 120"); XmlStorage::Restore(segmentation, stream); CPPUNIT_ASSERT_EQUAL(std::string("(90,90) (100,100) (110,110) (120,120) "), segmentation.boundsAsString()); } void testLoadFromWithMaxPos() { UnsizedSegmentation segmentation; std::istringstream stream("90 100 110 120"); XmlStorage::Restore(segmentation, stream); CPPUNIT_ASSERT_EQUAL(std::string("(90,90) (100,100) (110,110) (120,120) "), segmentation.boundsAsString()); } void testStoreOn_withinAnArray() { const TData onsets1[]={90, 100, 110, 120}; const TData onsets2[]={9, 10, 11}; CLAM::Array segmentations(2); segmentations[0].maxPosition(200); segmentations[0].takeArray(onsets1, onsets1+4); segmentations[1].maxPosition(20); segmentations[1].takeArray(onsets2, onsets2+3); std::ostringstream stream; XmlStorage::Dump(segmentations, "Segmentations", stream); CLAMTEST_ASSERT_XML_EQUAL( "" "90 100 110 120" "9 10 11" "" , stream.str()); } void testLoadFromWithoutMaxPos_withinAnArray() { CLAM::Array segmentations; std::istringstream stream( "" "90 100 110 120" "9 10 11" ""); XmlStorage::Restore(segmentations, stream); CPPUNIT_ASSERT_EQUAL(std::string("(90,90) (100,100) (110,110) (120,120) "), segmentations[0].boundsAsString()); CPPUNIT_ASSERT_EQUAL(std::string("(9,9) (10,10) (11,11) "), segmentations[1].boundsAsString()); } void testLoadFromWithMaxPos_withinAnArray() { CLAM::Array segmentations; std::istringstream stream( "" "90 100 110 120" "9 10 11" ""); XmlStorage::Restore(segmentations, stream); CPPUNIT_ASSERT_EQUAL(std::string("(90,90) (100,100) (110,110) (120,120) "), segmentations[0].boundsAsString()); CPPUNIT_ASSERT_EQUAL(std::string("(9,9) (10,10) (11,11) "), segmentations[1].boundsAsString()); } }; } clam-1.4.0/test/UnitTests/VisualizationTests/ContiguousSegmentationTest.cxx0000644000000000000000000005705411032460057026045 0ustar rootroot#include #include "cppUnitHelper.hxx" // necessary for the custom assert #include "ContiguousSegmentation.hxx" #include "XMLTestHelper.hxx" #include using CLAM::ContiguousSegmentation; using CLAM::XmlStorage; namespace CLAMTest { class ContiguousSegmentationTest; CPPUNIT_TEST_SUITE_REGISTRATION( ContiguousSegmentationTest ); class ContiguousSegmentationTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ContiguousSegmentationTest ); CPPUNIT_TEST( testConstructor ); CPPUNIT_TEST( testInsert_aPoint ); CPPUNIT_TEST( testInsert_inTheMiddle ); CPPUNIT_TEST( testInsert_beyondLimit ); CPPUNIT_TEST( testInsert_behindLimit ); CPPUNIT_TEST( testPickOffset_withExactValue ); CPPUNIT_TEST( testPickOffset_withNonMatchingValue ); CPPUNIT_TEST( testPickOffset_withinTolerance ); CPPUNIT_TEST( testPickOffset_withSeveralPointsWithinTolerance ); CPPUNIT_TEST( testPickOffset_outsideTheRange ); CPPUNIT_TEST( testPickOnset_withExactValue ); CPPUNIT_TEST( testPickOnset_withNonMatchingValue ); CPPUNIT_TEST( testPickOnset_withinTolerance ); CPPUNIT_TEST( testPickOnset_withSeveralPointsWithinTolerance ); CPPUNIT_TEST( testPickOnset_outsideTheRange ); CPPUNIT_TEST( testPickSegmentBody ); CPPUNIT_TEST( testPickSegmentBody_behindRange ); CPPUNIT_TEST( testPickSegmentBody_afterRange ); CPPUNIT_TEST( testPickSegmentBody_atABound ); CPPUNIT_TEST( testPickSegmentBody_atZeroBound ); CPPUNIT_TEST( testSelection ); CPPUNIT_TEST( testSelection_multiple ); CPPUNIT_TEST( testDeselection ); CPPUNIT_TEST( testInsert_movesSelection ); CPPUNIT_TEST( testClearSelection ); CPPUNIT_TEST( testDragOffset ); CPPUNIT_TEST( testDragOffset_beyondNextBound ); CPPUNIT_TEST( testDragOffset_beyondPreviousBound ); CPPUNIT_TEST( testDragOffset_ofLastBoundHasNoEffect ); CPPUNIT_TEST( testDragOffset_ofPreLastSegment ); CPPUNIT_TEST( testDragOffset_ofFirstBoundLimitIsZero ); CPPUNIT_TEST( testDragOnset ); CPPUNIT_TEST( testDragOnset_beyondNextBound ); CPPUNIT_TEST( testDragOnset_beyondPreviousBound ); CPPUNIT_TEST( testDragOnset_ofFirstBoundHasNoEffect ); CPPUNIT_TEST( testDragOnset_ofLastSegment ); CPPUNIT_TEST( testDragOnset_ofLastBoundLimitIsLength ); CPPUNIT_TEST( testRemove ); CPPUNIT_TEST( testRemove_movesSelection ); CPPUNIT_TEST( testRemove_removesRemovedSelection ); CPPUNIT_TEST( testRemove_firstSegment ); CPPUNIT_TEST( testRemove_lastSegmentExpandsPrevious ); CPPUNIT_TEST( testRemove_singleSegmentHasNoEffect ); CPPUNIT_TEST( testConstructor_putsCurrentAtZero ); CPPUNIT_TEST( testInsert_keepsCurrentAtZero ); CPPUNIT_TEST( testCurrent_changesCurrent ); CPPUNIT_TEST( testCurrent_aboveNSegmentsHasNoEffect ); CPPUNIT_TEST( testInsert_beforeCurrentCorrectsIt ); CPPUNIT_TEST( testRemove_beforeCurrentCorrectsIt ); CPPUNIT_TEST( testRemove_afterCurrentKeepsIt ); CPPUNIT_TEST( testRemove_justTheCurrentChangesIt ); CPPUNIT_TEST( testRemove_justTheCurrentButItIsZeroKeepsAtZero ); CPPUNIT_TEST( testInitialize_withGoodData ); CPPUNIT_TEST( testInitialize_withZero ); CPPUNIT_TEST( testInitialize_BeyondMax ); CPPUNIT_TEST( testStoreOn); CPPUNIT_TEST( testtakeArray); CPPUNIT_TEST( testLoadFromWithoutMaxPos ); CPPUNIT_TEST( testLoadFromWithMaxPos ); CPPUNIT_TEST(testStoreOn_withinAnArray); CPPUNIT_TEST(testMaxPosition_Initial); CPPUNIT_TEST(testLoadFromWithoutMaxPos_withinAnArray); CPPUNIT_TEST(testLoadFromWithMaxPos_withinAnArray); CPPUNIT_TEST_SUITE_END(); public: void testConstructor() { ContiguousSegmentation segmentation(200.0); CPPUNIT_ASSERT_EQUAL(std::string("(0,200) "), segmentation.boundsAsString()); } void testInsert_aPoint() { ContiguousSegmentation segmentation(200.0); unsigned pos = segmentation.insert(100); CPPUNIT_ASSERT_EQUAL(1u, pos); CPPUNIT_ASSERT_EQUAL(std::string("(0,100) (100,200) "), segmentation.boundsAsString()); } void testInsert_inTheMiddle() { ContiguousSegmentation segmentation(200.0); segmentation.insert(50); segmentation.insert(150); unsigned pos = segmentation.insert(100); CPPUNIT_ASSERT_EQUAL(2u, pos); CPPUNIT_ASSERT_EQUAL(std::string("(0,50) (50,100) (100,150) (150,200) "), segmentation.boundsAsString()); } void testInsert_beyondLimit() { ContiguousSegmentation segmentation(200.0); try { segmentation.insert(400); CPPUNIT_FAIL("Should have thrown an exception"); } catch (ContiguousSegmentation::InsertedOutOfBounds & e) { CPPUNIT_ASSERT_EQUAL(std::string("Segmentation point inserted out of limits"), std::string(e.what())); } CPPUNIT_ASSERT_EQUAL(std::string("(0,200) "), segmentation.boundsAsString()); } void testInsert_behindLimit() { ContiguousSegmentation segmentation(200.0); try { segmentation.insert(-0.1); CPPUNIT_FAIL("Should have thrown an exception"); } catch (ContiguousSegmentation::InsertedOutOfBounds & e) { CPPUNIT_ASSERT_EQUAL(std::string("Segmentation point inserted out of limits"), std::string(e.what())); } CPPUNIT_ASSERT_EQUAL(std::string("(0,200) "), segmentation.boundsAsString()); } void testPickOffset_withExactValue() { ContiguousSegmentation segmentation(200.0); segmentation.insert(50); segmentation.insert(100); segmentation.insert(150); unsigned position= segmentation.pickOffset(100,0.5); CPPUNIT_ASSERT_EQUAL(1u, position); } void testPickOffset_withNonMatchingValue() { ContiguousSegmentation segmentation(200.0); segmentation.insert(50); segmentation.insert(100); segmentation.insert(150); unsigned position= segmentation.pickOffset(125,0.5); CPPUNIT_ASSERT_EQUAL(4u, position); } void testPickOffset_withinTolerance() { ContiguousSegmentation segmentation(200.0); segmentation.insert(50); segmentation.insert(100); segmentation.insert(150); unsigned position= segmentation.pickOffset(100.2,0.5); CPPUNIT_ASSERT_EQUAL(1u, position); } void testPickOffset_withSeveralPointsWithinTolerance() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); unsigned position= segmentation.pickOffset(101,20); CPPUNIT_ASSERT_EQUAL(1u, position); } void testPickOffset_outsideTheRange() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); unsigned position= segmentation.pickOffset(221,20); CPPUNIT_ASSERT_EQUAL(4u, position); } void testPickOnset_withExactValue() { ContiguousSegmentation segmentation(200.0); segmentation.insert(50); segmentation.insert(100); segmentation.insert(150); unsigned position= segmentation.pickOnset(100,0.5); CPPUNIT_ASSERT_EQUAL(2u, position); } void testPickOnset_withNonMatchingValue() { ContiguousSegmentation segmentation(200.0); segmentation.insert(50); segmentation.insert(100); segmentation.insert(150); unsigned position= segmentation.pickOnset(125,0.5); CPPUNIT_ASSERT_EQUAL(4u, position); } void testPickOnset_withinTolerance() { ContiguousSegmentation segmentation(200.0); segmentation.insert(50); segmentation.insert(100); segmentation.insert(150); unsigned position= segmentation.pickOnset(100.2,0.5); CPPUNIT_ASSERT_EQUAL(2u, position); } void testPickOnset_withSeveralPointsWithinTolerance() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); unsigned position= segmentation.pickOnset(101,20); CPPUNIT_ASSERT_EQUAL(2u, position); } void testPickOnset_outsideTheRange() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); unsigned position= segmentation.pickOnset(221,20); CPPUNIT_ASSERT_EQUAL(4u, position); } void testPickSegmentBody() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); unsigned position= segmentation.pickSegmentBody(102); CPPUNIT_ASSERT_EQUAL(2u, position); } void testPickSegmentBody_behindRange() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); unsigned position= segmentation.pickSegmentBody(-1); CPPUNIT_ASSERT_EQUAL(4u, position); } void testPickSegmentBody_afterRange() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); unsigned position= segmentation.pickSegmentBody(201); CPPUNIT_ASSERT_EQUAL(4u, position); } void testPickSegmentBody_atABound() { // This behaviour is not specified just to know what happens ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); unsigned position= segmentation.pickSegmentBody(100); CPPUNIT_ASSERT_EQUAL(1u, position); } void testPickSegmentBody_atZeroBound() { // This behaviour is not specified just to know what happens ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); unsigned position= segmentation.pickSegmentBody(0); CPPUNIT_ASSERT_EQUAL(0u, position); } void testSelection() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.select(2); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) +(100,110) (110,200) "), segmentation.boundsAsString()); } void testSelection_multiple() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.select(2); segmentation.select(1); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) +(90,100) +(100,110) (110,200) "), segmentation.boundsAsString()); } void testDeselection() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.select(2); segmentation.select(1); segmentation.deselect(2); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) +(90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testInsert_movesSelection() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.select(1); segmentation.select(2); segmentation.insert(95); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) +(90,95) (95,100) +(100,110) (110,200) "), segmentation.boundsAsString()); } void testClearSelection() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.select(1); segmentation.select(2); segmentation.clearSelection(); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testDragOffset() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.dragOffset(1,105); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,105) (105,110) (110,200) "), segmentation.boundsAsString()); } void testDragOffset_beyondNextBound() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.dragOffset(1,115); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,110) (110,110) (110,200) "), segmentation.boundsAsString()); } void testDragOffset_beyondPreviousBound() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.dragOffset(1,85); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,90) (90,110) (110,200) "), segmentation.boundsAsString()); } void testDragOffset_ofLastBoundHasNoEffect() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.dragOffset(4,190); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testDragOffset_ofPreLastSegment() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.dragOffset(3,114); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testDragOffset_ofFirstBoundLimitIsZero() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.dragOffset(0,-12); CPPUNIT_ASSERT_EQUAL(std::string("(0,0) (0,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testDragOnset() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.dragOnset(2,105); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,105) (105,110) (110,200) "), segmentation.boundsAsString()); } void testDragOnset_beyondNextBound() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.dragOnset(2,115); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,110) (110,110) (110,200) "), segmentation.boundsAsString()); } void testDragOnset_beyondPreviousBound() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.dragOnset(2,85); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,90) (90,110) (110,200) "), segmentation.boundsAsString()); } void testDragOnset_ofFirstBoundHasNoEffect() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.dragOnset(0,10); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testDragOnset_ofLastSegment() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.dragOnset(3,114); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,114) (114,200) "), segmentation.boundsAsString()); } void testDragOnset_ofLastBoundLimitIsLength() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.dragOnset(3,210); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,200) (200,200) "), segmentation.boundsAsString()); } void testRemove() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); segmentation.remove(2); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,110) (110,200) "), segmentation.boundsAsString()); } void testRemove_movesSelection() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.select(1); segmentation.select(3); segmentation.remove(2); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) +(90,110) +(110,200) "), segmentation.boundsAsString()); } void testRemove_removesRemovedSelection() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.select(2); segmentation.remove(2); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,110) (110,200) "), segmentation.boundsAsString()); } void testRemove_firstSegment() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.select(1); segmentation.select(3); segmentation.remove(0); CPPUNIT_ASSERT_EQUAL(std::string("+(0,100) (100,110) +(110,200) "), segmentation.boundsAsString()); } void testRemove_lastSegmentExpandsPrevious() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.select(1); segmentation.select(3); segmentation.remove(3); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) +(90,100) (100,200) "), segmentation.boundsAsString()); } void testRemove_singleSegmentHasNoEffect() { ContiguousSegmentation segmentation(200.0); segmentation.remove(0); CPPUNIT_ASSERT_EQUAL(std::string("(0,200) "), segmentation.boundsAsString()); } void testConstructor_putsCurrentAtZero() { ContiguousSegmentation segmentation(200.0); CPPUNIT_ASSERT_EQUAL(0u, segmentation.current()); } void testInsert_keepsCurrentAtZero() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); CPPUNIT_ASSERT_EQUAL(0u, segmentation.current()); } void testCurrent_changesCurrent() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.current(2); CPPUNIT_ASSERT_EQUAL(2u, segmentation.current()); } void testCurrent_aboveNSegmentsHasNoEffect() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.current(2); segmentation.current(4); CPPUNIT_ASSERT_EQUAL(2u, segmentation.current()); } void testInsert_beforeCurrentCorrectsIt() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.current(2); segmentation.insert(95); CPPUNIT_ASSERT_EQUAL(3u, segmentation.current()); } void testRemove_beforeCurrentCorrectsIt() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.current(2); segmentation.remove(1); CPPUNIT_ASSERT_EQUAL(1u, segmentation.current()); } void testRemove_afterCurrentKeepsIt() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.current(2); segmentation.remove(3); CPPUNIT_ASSERT_EQUAL(2u, segmentation.current()); } void testRemove_justTheCurrentChangesIt() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.current(2); segmentation.remove(2); CPPUNIT_ASSERT_EQUAL(1u, segmentation.current()); } void testRemove_justTheCurrentButItIsZeroKeepsAtZero() { ContiguousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.current(0); segmentation.remove(0); CPPUNIT_ASSERT_EQUAL(0u, segmentation.current()); } void testInitialize_withGoodData() { const TData onsets[] = {90,100,110}; ContiguousSegmentation segmentation(200, onsets, onsets+3); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testInitialize_withZero() { const TData onsets[] = {0,90,100,110}; try { ContiguousSegmentation segmentation(200, onsets, onsets+4); CPPUNIT_FAIL("Should have thrown an exception"); } catch (ContiguousSegmentation::InsertedOutOfBounds & e) { CPPUNIT_ASSERT_EQUAL(std::string("Segmentation point inserted out of limits"), std::string(e.what())); } } void testInitialize_BeyondMax() { const TData onsets[] = {90,100,110, 201}; try { ContiguousSegmentation segmentation(200, onsets, onsets+4); CPPUNIT_FAIL("Should have thrown an exception"); } catch (ContiguousSegmentation::InsertedOutOfBounds & e) { CPPUNIT_ASSERT_EQUAL(std::string("Segmentation point inserted out of limits"), std::string(e.what())); } } void testStoreOn() { const TData onsets[]={90, 100, 110}; ContiguousSegmentation segmentation(200, onsets, onsets+3); std::ostringstream stream; XmlStorage::Dump(segmentation, "Segmentation", stream); CLAMTEST_ASSERT_XML_EQUAL( "90 100 110" , stream.str()); } void testtakeArray() { const TData bounds[]={90, 100, 110, 120}; ContiguousSegmentation segmentation(200); segmentation.takeArray(bounds, bounds+4); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,120) (120,200) "), segmentation.boundsAsString()); } void testLoadFromWithoutMaxPos() { ContiguousSegmentation segmentation(200); std::istringstream stream("90 100 110"); XmlStorage::Restore(segmentation, stream); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,100000) "), segmentation.boundsAsString()); } void testLoadFromWithMaxPos() { ContiguousSegmentation segmentation; std::istringstream stream("90 100 110"); XmlStorage::Restore(segmentation, stream); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testStoreOn_withinAnArray() { const TData onsets1[]={90, 100, 110, 120}; const TData onsets2[]={9, 10, 11}; CLAM::Array segmentations(2); segmentations[0].maxPosition(200); segmentations[0].takeArray(onsets1, onsets1+4); segmentations[1].maxPosition(20); segmentations[1].takeArray(onsets2, onsets2+3); std::ostringstream stream; XmlStorage::Dump(segmentations, "Segmentations", stream); CLAMTEST_ASSERT_XML_EQUAL( "" "90 100 110 120" "9 10 11" "" , stream.str()); } void testLoadFromWithoutMaxPos_withinAnArray() { CLAM::Array segmentations; std::istringstream stream( "" "90 100 110 120" "9 10 11" ""); XmlStorage::Restore(segmentations, stream); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,120) (120,100000) "), segmentations[0].boundsAsString()); CPPUNIT_ASSERT_EQUAL(std::string("(0,9) (9,10) (10,11) (11,100000) "), segmentations[1].boundsAsString()); } void testLoadFromWithMaxPos_withinAnArray() { CLAM::Array segmentations; std::istringstream stream( "" "90 100 110 120" "9 10 11" ""); XmlStorage::Restore(segmentations, stream); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,120) (120,200) "), segmentations[0].boundsAsString()); CPPUNIT_ASSERT_EQUAL(std::string("(0,9) (9,10) (10,11) (11,20) "), segmentations[1].boundsAsString()); } void testMaxPosition_Initial() { ContiguousSegmentation segmentation; segmentation.maxPosition(200); CPPUNIT_ASSERT_EQUAL(std::string("(0,200) "), segmentation.boundsAsString()); } }; } clam-1.4.0/test/UnitTests/VisualizationTests/DiscontinuousSegmentationTest.cxx0000644000000000000000000006504211032460057026550 0ustar rootroot#include #include "cppUnitHelper.hxx" // necessary for the custom assert #include "DiscontinuousSegmentation.hxx" #include "XMLTestHelper.hxx" #include using CLAM::DiscontinuousSegmentation; using CLAM::XmlStorage; namespace CLAMTest { class DiscontinuousSegmentationTest; CPPUNIT_TEST_SUITE_REGISTRATION( DiscontinuousSegmentationTest ); class DiscontinuousSegmentationTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( DiscontinuousSegmentationTest ); CPPUNIT_TEST( testConstructor ); CPPUNIT_TEST( testInsert_atZero ); CPPUNIT_TEST( testInsert_inTheMiddleOfAnExistingSegment ); CPPUNIT_TEST( testInsert_beyondLimit ); CPPUNIT_TEST( testInsert_behindLimit ); CPPUNIT_TEST( testInit_withASortedListsOfPoints ); CPPUNIT_TEST( testInit_withAnOverlap ); CPPUNIT_TEST( testInit_withUnsortedOnsetOffsetPair ); CPPUNIT_TEST( testInit_withOutOfBoundsOffset ); CPPUNIT_TEST( testInit_withOddNumberOfBounds ); CPPUNIT_TEST( testPickOffset_withExactValue ); CPPUNIT_TEST( testPickOffset_withNonMatchingValue ); CPPUNIT_TEST( testPickOffset_withinTolerance ); CPPUNIT_TEST( testPickOffset_withSeveralPointsWithinTolerance ); CPPUNIT_TEST( testPickOffset_outsideTheRange ); CPPUNIT_TEST( testPickOnset_withExactValue ); CPPUNIT_TEST( testPickOnset_withNonMatchingValue ); CPPUNIT_TEST( testPickOnset_withinTolerance ); CPPUNIT_TEST( testPickOnset_withSeveralPointsWithinTolerance ); CPPUNIT_TEST( testPickOnset_outsideTheRange ); CPPUNIT_TEST( testPickSegmentBody ); CPPUNIT_TEST( testPickSegmentBody_behindRange ); CPPUNIT_TEST( testPickSegmentBody_afterRange ); CPPUNIT_TEST( testPickSegmentBody_atABound ); CPPUNIT_TEST( testPickSegmentBody_atZeroBound ); CPPUNIT_TEST( testPickSegmentBody_atGap ); CPPUNIT_TEST( testSelection ); CPPUNIT_TEST( testSelection_multiple ); CPPUNIT_TEST( testDeselection ); CPPUNIT_TEST( testInsert_movesSelection ); CPPUNIT_TEST( testClearSelection ); CPPUNIT_TEST( testDragOnset_ofFirstBoundHasEffect ); CPPUNIT_TEST( testDragOffset_ofLastBoundHasEffect ); CPPUNIT_TEST( testDragOnset ); CPPUNIT_TEST( testDragOffset ); CPPUNIT_TEST( testDragOnset_thatDoesNotExist ); CPPUNIT_TEST( testDragOffset_thatDoesNotExist ); CPPUNIT_TEST( testDragOnset_toLeftLimitedByPreviousOffset ); CPPUNIT_TEST( testDragOnset_toLeftLimitedByZeroWhenFirstOne ); CPPUNIT_TEST( testDragOnset_toRightLimitedByOwnOffset ); CPPUNIT_TEST( testDragOffset_toRightLimitedByNextOnset ); CPPUNIT_TEST( testDragOffset_toRightLimitedByMaxWhenLastOne ); CPPUNIT_TEST( testDragOffset_toLeftLimitedByOwnOnset ); CPPUNIT_TEST( testRemove ); CPPUNIT_TEST( testRemove_movesSelection ); CPPUNIT_TEST( testRemove_removesRemovedSelection ); CPPUNIT_TEST( testRemove_firstSegment ); CPPUNIT_TEST( testRemove_lastSegmentExpandsPrevious ); CPPUNIT_TEST( testRemove_singleSegmentHasEffect ); CPPUNIT_TEST( testConstructor_putsCurrentAtZero ); CPPUNIT_TEST( testInsert_keepsCurrentAtZero ); CPPUNIT_TEST( testCurrent_changesCurrent ); CPPUNIT_TEST( testCurrent_aboveNSegmentsHasNoEffect ); CPPUNIT_TEST( testInsert_beforeCurrentCorrectsIt ); CPPUNIT_TEST( testRemove_beforeCurrentCorrectsIt ); CPPUNIT_TEST( testRemove_afterCurrentKeepsIt ); CPPUNIT_TEST( testRemove_justTheCurrentChangesIt ); CPPUNIT_TEST( testRemove_justTheCurrentButItIsZeroKeepsAtZero ); CPPUNIT_TEST( testInsert_onTheMiddleOfAFrame ); CPPUNIT_TEST( testInsert_onGapAtTheBegining ); CPPUNIT_TEST( testInsert_onGapAtTheBeginingMovesCurrentWhenAfter ); CPPUNIT_TEST( testInsert_onGapInBetweenSegments ); CPPUNIT_TEST( testStoreOn); // TODO: This test crashes in some boxes CPPUNIT_TEST( testtakeArray); CPPUNIT_TEST(testLoadFromWithoutMaxPos); CPPUNIT_TEST(testLoadFromWithMaxPos); CPPUNIT_TEST(testStoreOn_withinAnArray); CPPUNIT_TEST(testLoadFromWithoutMaxPos_withinAnArray); CPPUNIT_TEST(testLoadFromWithMaxPos_withinAnArray); CPPUNIT_TEST_SUITE_END(); public: void testConstructor() { DiscontinuousSegmentation segmentation(200.0); CPPUNIT_ASSERT_EQUAL(std::string(""), segmentation.boundsAsString()); } void testInsert_atZero() { DiscontinuousSegmentation segmentation(200.0); unsigned pos = segmentation.insert(0); CPPUNIT_ASSERT_EQUAL(0u, pos); CPPUNIT_ASSERT_EQUAL(std::string("(0,200) "), segmentation.boundsAsString()); } void testInsert_inTheMiddleOfAnExistingSegment() { DiscontinuousSegmentation segmentation(200.0); segmentation.insert(0); unsigned pos = segmentation.insert(100); CPPUNIT_ASSERT_EQUAL(1u, pos); CPPUNIT_ASSERT_EQUAL(std::string("(0,100) (100,200) "), segmentation.boundsAsString()); } void testInsert_beyondLimit() { DiscontinuousSegmentation segmentation(200.0); try { segmentation.insert(400); CPPUNIT_FAIL("Should have thrown an exception"); } catch (DiscontinuousSegmentation::InsertedOutOfBounds & e) { CPPUNIT_ASSERT_EQUAL(std::string("Segmentation point inserted out of limits"), std::string(e.what())); } CPPUNIT_ASSERT_EQUAL(std::string(""), segmentation.boundsAsString()); } void testInsert_behindLimit() { DiscontinuousSegmentation segmentation(200.0); try { segmentation.insert(-0.1); CPPUNIT_FAIL("Should have thrown an exception"); } catch (DiscontinuousSegmentation::InsertedOutOfBounds & e) { CPPUNIT_ASSERT_EQUAL(std::string("Segmentation point inserted out of limits"), std::string(e.what())); } CPPUNIT_ASSERT_EQUAL(std::string(""), segmentation.boundsAsString()); } void testInit_withASortedListsOfPoints() { const TData bounds[] = {50,90,100,150}; DiscontinuousSegmentation segmentation(200.0, bounds, bounds+4); CPPUNIT_ASSERT_EQUAL(std::string("(50,90) (100,150) "), segmentation.boundsAsString()); } void testInit_withAnOverlap() { try { const TData bounds[] = {50,100,90,150}; DiscontinuousSegmentation segmentation(200.0, bounds, bounds+4); CPPUNIT_FAIL("Should have thrown an exception"); } catch (DiscontinuousSegmentation::MissplacedOnset & e) { CPPUNIT_ASSERT_EQUAL(std::string("Segment 1 starts at 90 overlapping previous segment which ends at 100"), std::string(e.what())); } } void testInit_withUnsortedOnsetOffsetPair() { try { const TData bounds[] = {50,90,150,100}; DiscontinuousSegmentation segmentation(200.0, bounds, bounds+4); CPPUNIT_FAIL("Should have thrown an exception"); } catch (DiscontinuousSegmentation::MissplacedOffset & e) { CPPUNIT_ASSERT_EQUAL(std::string("Segment 1 starts at 150 but ends before that, at 100"), std::string(e.what())); } } void testInit_withOutOfBoundsOffset() { try { const TData bounds[] = {50,90,150,201}; DiscontinuousSegmentation segmentation(200.0, bounds, bounds+4); CPPUNIT_FAIL("Should have thrown an exception"); } catch (DiscontinuousSegmentation::InsertedOutOfBounds & e) { CPPUNIT_ASSERT_EQUAL(std::string("Segmentation point inserted out of limits"), std::string(e.what())); } } void testInit_withOddNumberOfBounds() { try { const TData bounds[] = {50,90,100,150}; DiscontinuousSegmentation segmentation(200.0, bounds, bounds+3); CPPUNIT_FAIL("Should have thrown an exception"); } catch (DiscontinuousSegmentation::OffsetMissing & e) { CPPUNIT_ASSERT_EQUAL(std::string("Odd number of segmentation points, every segment beggining must be followed by its ending"), std::string(e.what())); } } void testPickOffset_withExactValue() { const TData divisions[]={0,50,50,100,100,150,150,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickOffset(100,0.5); CPPUNIT_ASSERT_EQUAL(1u, position); } void testPickOffset_withNonMatchingValue() { const TData divisions[]={0,50,50,100,100,150,150,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickOffset(125,0.5); CPPUNIT_ASSERT_EQUAL(4u, position); } void testPickOffset_withinTolerance() { const TData divisions[]={0,50,50,100,100,150,150,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickOffset(100.2,0.5); CPPUNIT_ASSERT_EQUAL(1u, position); } void testPickOffset_withSeveralPointsWithinTolerance() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickOffset(101,20); CPPUNIT_ASSERT_EQUAL(1u, position); } void testPickOffset_outsideTheRange() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickOffset(221,20); CPPUNIT_ASSERT_EQUAL(4u, position); } void testPickOnset_withExactValue() { const TData divisions[]={0,50,50,100,100,150,150,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickOnset(100,0.5); CPPUNIT_ASSERT_EQUAL(2u, position); } void testPickOnset_withNonMatchingValue() { const TData divisions[]={0,50,50,100,100,150,150,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickOnset(125,0.5); CPPUNIT_ASSERT_EQUAL(4u, position); } void testPickOnset_withinTolerance() { const TData divisions[]={0,50,50,100,100,150,150,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickOnset(100.2,0.5); CPPUNIT_ASSERT_EQUAL(2u, position); } void testPickOnset_withSeveralPointsWithinTolerance() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickOnset(101,20); CPPUNIT_ASSERT_EQUAL(2u, position); } void testPickOnset_outsideTheRange() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickOnset(221,20); CPPUNIT_ASSERT_EQUAL(4u, position); } void testPickSegmentBody() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickSegmentBody(102); CPPUNIT_ASSERT_EQUAL(2u, position); } void testPickSegmentBody_behindRange() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickSegmentBody(-1); CPPUNIT_ASSERT_EQUAL(4u, position); } void testPickSegmentBody_afterRange() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickSegmentBody(201); CPPUNIT_ASSERT_EQUAL(4u, position); } void testPickSegmentBody_atABound() { // This behaviour is not specified just to know what happens const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickSegmentBody(100); CPPUNIT_ASSERT_EQUAL(1u, position); } void testPickSegmentBody_atZeroBound() { // This behaviour is not specified just to know what happens const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); unsigned position= segmentation.pickSegmentBody(0); CPPUNIT_ASSERT_EQUAL(0u, position); } void testPickSegmentBody_atGap() { const TData divisions[]={90,100,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+4); unsigned position= segmentation.pickSegmentBody(105); CPPUNIT_ASSERT_EQUAL(2u, position); } void testSelection() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.select(2); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) +(100,110) (110,200) "), segmentation.boundsAsString()); } void testSelection_multiple() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.select(2); segmentation.select(1); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) +(90,100) +(100,110) (110,200) "), segmentation.boundsAsString()); } void testDeselection() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.select(2); segmentation.select(1); segmentation.deselect(2); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) +(90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testInsert_movesSelection() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.select(1); segmentation.select(2); segmentation.insert(95); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) +(90,95) (95,100) +(100,110) (110,200) "), segmentation.boundsAsString()); } void testClearSelection() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.select(1); segmentation.select(2); segmentation.clearSelection(); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testDragOffset_ofLastBoundHasEffect() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.dragOffset(3,190); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,190) "), segmentation.boundsAsString()); } void testDragOnset_ofFirstBoundHasEffect() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.dragOnset(0,10); CPPUNIT_ASSERT_EQUAL(std::string("(10,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testDragOffset() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.dragOffset(1,95); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,95) (100,110) (110,200) "), segmentation.boundsAsString()); } void testDragOnset() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.dragOnset(2,105); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (105,110) (110,200) "), segmentation.boundsAsString()); } void testDragOnset_thatDoesNotExist() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.dragOnset(4,150); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testDragOffset_thatDoesNotExist() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.dragOffset(4,150); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testDragOnset_toLeftLimitedByPreviousOffset() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.dragOnset(2,95); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testDragOnset_toLeftLimitedByZeroWhenFirstOne() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.dragOnset(0,-10); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testDragOnset_toRightLimitedByOwnOffset() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.dragOnset(2,115); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (110,110) (110,200) "), segmentation.boundsAsString()); } void testDragOffset_toRightLimitedByNextOnset() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.dragOffset(2,115); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testDragOffset_toRightLimitedByMaxWhenLastOne() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.dragOffset(3,115); segmentation.dragOffset(3,205); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); } void testDragOffset_toLeftLimitedByOwnOnset() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.dragOffset(2,95); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,100) (110,200) "), segmentation.boundsAsString()); } void testRemove() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (100,110) (110,200) "), segmentation.boundsAsString()); segmentation.remove(2); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (110,200) "), segmentation.boundsAsString()); } void testRemove_movesSelection() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.select(1); segmentation.select(3); segmentation.remove(2); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) +(90,100) +(110,200) "), segmentation.boundsAsString()); } void testRemove_removesRemovedSelection() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.select(2); segmentation.remove(2); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) (90,100) (110,200) "), segmentation.boundsAsString()); } void testRemove_firstSegment() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.select(1); segmentation.select(3); segmentation.remove(0); CPPUNIT_ASSERT_EQUAL(std::string("+(90,100) (100,110) +(110,200) "), segmentation.boundsAsString()); } void testRemove_lastSegmentExpandsPrevious() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.select(1); segmentation.select(3); segmentation.remove(3); CPPUNIT_ASSERT_EQUAL(std::string("(0,90) +(90,100) (100,110) "), segmentation.boundsAsString()); } void testRemove_singleSegmentHasEffect() { DiscontinuousSegmentation segmentation(200.0); segmentation.insert(0); segmentation.remove(0); CPPUNIT_ASSERT_EQUAL(std::string(""), segmentation.boundsAsString()); } void testConstructor_putsCurrentAtZero() { DiscontinuousSegmentation segmentation(200.0); CPPUNIT_ASSERT_EQUAL(0u, segmentation.current()); } void testInsert_keepsCurrentAtZero() { DiscontinuousSegmentation segmentation(200.0); segmentation.insert(0); segmentation.insert(90); CPPUNIT_ASSERT_EQUAL(0u, segmentation.current()); } void testCurrent_changesCurrent() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.current(2); CPPUNIT_ASSERT_EQUAL(2u, segmentation.current()); } void testCurrent_aboveNSegmentsHasNoEffect() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.current(2); segmentation.current(4); CPPUNIT_ASSERT_EQUAL(2u, segmentation.current()); } void testInsert_beforeCurrentCorrectsIt() { const TData divisions[]={0,90,90,100,100,110,110,200}; DiscontinuousSegmentation segmentation(200.0, divisions, divisions+8); segmentation.current(2); segmentation.insert(95); CPPUNIT_ASSERT_EQUAL(3u, segmentation.current()); } void testRemove_beforeCurrentCorrectsIt() { DiscontinuousSegmentation segmentation(200.0); segmentation.insert(0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.current(2); segmentation.remove(1); CPPUNIT_ASSERT_EQUAL(1u, segmentation.current()); } void testRemove_afterCurrentKeepsIt() { DiscontinuousSegmentation segmentation(200.0); segmentation.insert(0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.current(2); segmentation.remove(3); CPPUNIT_ASSERT_EQUAL(2u, segmentation.current()); } void testRemove_justTheCurrentChangesIt() { DiscontinuousSegmentation segmentation(200.0); segmentation.insert(0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.current(2); segmentation.remove(2); CPPUNIT_ASSERT_EQUAL(1u, segmentation.current()); } void testRemove_justTheCurrentButItIsZeroKeepsAtZero() { DiscontinuousSegmentation segmentation(200.0); segmentation.insert(0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(110); segmentation.current(0); segmentation.remove(0); CPPUNIT_ASSERT_EQUAL(0u, segmentation.current()); } void testInsert_onTheMiddleOfAFrame() { DiscontinuousSegmentation segmentation(200.0); segmentation.insert(100); segmentation.insert(150); segmentation.remove(1); unsigned pos = segmentation.insert(130); CPPUNIT_ASSERT_EQUAL(1u, pos); CPPUNIT_ASSERT_EQUAL(std::string("(100,130) (130,150) "), segmentation.boundsAsString()); } void testInsert_onGapAtTheBegining() { DiscontinuousSegmentation segmentation(200.0); segmentation.insert(100); segmentation.insert(150); segmentation.remove(1); unsigned pos = segmentation.insert(0); CPPUNIT_ASSERT_EQUAL(0u, pos); CPPUNIT_ASSERT_EQUAL(std::string("(0,100) (100,150) "), segmentation.boundsAsString()); } void testInsert_onGapAtTheBeginingMovesCurrentWhenAfter() { DiscontinuousSegmentation segmentation(200.0); segmentation.insert(100); segmentation.insert(150); segmentation.remove(1); segmentation.current(0); segmentation.insert(0); CPPUNIT_ASSERT_EQUAL(1u, segmentation.current()); } void testInsert_onGapInBetweenSegments() { DiscontinuousSegmentation segmentation(200.0); segmentation.insert(90); segmentation.insert(100); segmentation.insert(150); segmentation.remove(1); segmentation.current(0); unsigned pos = segmentation.insert(120); CPPUNIT_ASSERT_EQUAL(1u, pos); CPPUNIT_ASSERT_EQUAL(std::string("(90,100) (120,150) (150,200) "), segmentation.boundsAsString()); } void testStoreOn() { const TData bounds[]={90, 100, 110, 120}; DiscontinuousSegmentation segmentationEven(200, bounds, bounds+4); std::ostringstream stream; XmlStorage::Dump(segmentationEven, "Segmentation", stream); CLAMTEST_ASSERT_XML_EQUAL( "90 100 110 120" , stream.str()); } void testtakeArray() { const TData bounds[]={90, 100, 110, 120}; DiscontinuousSegmentation segmentationEven(200); segmentationEven.takeArray(bounds, bounds+4); CPPUNIT_ASSERT_EQUAL(std::string("(90,100) (110,120) "), segmentationEven.boundsAsString()); } void testLoadFromWithoutMaxPos() { DiscontinuousSegmentation segmentation(200); std::istringstream stream("90 100 110 120"); XmlStorage::Restore(segmentation, stream); CPPUNIT_ASSERT_EQUAL(std::string("(90,100) (110,120) "), segmentation.boundsAsString()); } void testLoadFromWithMaxPos() { DiscontinuousSegmentation segmentation; std::istringstream stream("90 100 110 120"); XmlStorage::Restore(segmentation, stream); CPPUNIT_ASSERT_EQUAL(std::string("(90,100) (110,120) "), segmentation.boundsAsString()); } void testStoreOn_withinAnArray() { const TData onsets1[]={90, 100, 110, 120}; const TData onsets2[]={9, 10, 11, 12, 16, 18}; CLAM::Array segmentations(2); segmentations[0].maxPosition(200); segmentations[0].takeArray(onsets1, onsets1+4); segmentations[1].maxPosition(20); segmentations[1].takeArray(onsets2, onsets2+6); std::ostringstream stream; XmlStorage::Dump(segmentations, "Segmentations", stream); CLAMTEST_ASSERT_XML_EQUAL( "" "90 100 110 120" "9 10 11 12 16 18" "" , stream.str()); } void testLoadFromWithoutMaxPos_withinAnArray() { CLAM::Array segmentations; std::istringstream stream( "" "90 100 110 120" "9 10 11 12 16 18" ""); XmlStorage::Restore(segmentations, stream); CPPUNIT_ASSERT_EQUAL(std::string("(90,100) (110,120) "), segmentations[0].boundsAsString()); CPPUNIT_ASSERT_EQUAL(std::string("(9,10) (11,12) (16,18) "), segmentations[1].boundsAsString()); } void testLoadFromWithMaxPos_withinAnArray() { CLAM::Array segmentations; std::istringstream stream( "" "90 100 110 120" "9 10 11 12 16 18" ""); XmlStorage::Restore(segmentations, stream); CPPUNIT_ASSERT_EQUAL(std::string("(90,100) (110,120) "), segmentations[0].boundsAsString()); CPPUNIT_ASSERT_EQUAL(std::string("(9,10) (11,12) (16,18) "), segmentations[1].boundsAsString()); } }; } clam-1.4.0/test/UnitTests/ToolsTests/0000755000000000000000000000000011344231435016172 5ustar rootrootclam-1.4.0/test/UnitTests/ToolsTests/AudioFileTest.cxx0000644000000000000000000003320310635463001021416 0ustar rootroot#include #include "cppUnitHelper.hxx" #include "AudioFile.hxx" // CLAM #include "AudioFileHeader.hxx" // CLAM #include "AudioFileFormats.hxx" // CLAM #include "XMLStorage.hxx" // CLAM #include namespace CLAMTest { class AudioFileTest; CPPUNIT_TEST_SUITE_REGISTRATION( AudioFileTest ); class AudioFileTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( AudioFileTest ); CPPUNIT_TEST( testOpenExisting_FileExists_and_Is_PCM ); CPPUNIT_TEST( testOpenExisting_FileExists_and_Is_OggVorbis ); CPPUNIT_TEST( testOpenExisting_FileExists_and_Is_Mpeg ); CPPUNIT_TEST( testOpenExisting_FileExists_NotSpurious_Mpeg ); CPPUNIT_TEST( testOpenExisting_FileDoesNotExist_UnrecognizedFormat ); CPPUNIT_TEST( testIsReadable_with_strangeThings ); CPPUNIT_TEST( testGetHeader_HeaderIsRight_PCM ); CPPUNIT_TEST( testGetHeader_HeaderIsRight_OggVorbis ); CPPUNIT_TEST( testGetHeader_HeaderIsRight_Mpeg ); CPPUNIT_TEST( testGetHeader_NoHeaderWhenFileIsUnreadable ); CPPUNIT_TEST( testGetHeader_NoHeaderWhenFileIsUnreadable_AfterOneSuccessful ); CPPUNIT_TEST( testCreateNew_UserDefinesHeaderForWriting_PCM_RightCodecIsDeduced ); CPPUNIT_TEST( testCreateNew_UserDefinesHeaderForWriting_Ogg_RightCodecIsDeduced ); CPPUNIT_TEST( testCreateNew_WithoutSampleRate_Fails ); CPPUNIT_TEST( testCreateNew_WithoutChannels_IsOK ); CPPUNIT_TEST( testCreateNew_WithoutFormat_Fails ); CPPUNIT_TEST( testCreateNew_SetValues_WAV ); CPPUNIT_TEST( testCreateNew_SetValues_AIFF ); CPPUNIT_TEST( testCreateNew_SetValues_OggVorbis ); CPPUNIT_TEST( testCreateNew_SetValues_WAV_AreWritable ); CPPUNIT_TEST( testCreateNew_SetValues_AIFF_AreWritable ); CPPUNIT_TEST( testCreateNew_SetValues_OggVorbis_AreWritable ); CPPUNIT_TEST( testIsWritable_ReturnsTrue_PCM_WithReasonableHeader ); CPPUNIT_TEST( testIsWritable_ReturnsFalse_PCM_TooManyChannels ); CPPUNIT_TEST( testIsWritable_ReturnsFalse_PCM_TooFewChannels ); CPPUNIT_TEST( testTextDescriptorsExtraction_From_OggVorbis ); CPPUNIT_TEST( testTextDescriptorsExtraction_From_Mpeg ); CPPUNIT_TEST_SUITE_END(); public: void setUp() { mPathToTestData = GetTestDataDirectory(); } void tearDown() { } protected: std::string mPathToTestData; private: // test cases void testIsReadable_with_strangeThings() { CLAM::AudioFileSource file; file.OpenExisting( std::string( mPathToTestData + "Image.jpg" ) ); CPPUNIT_ASSERT_EQUAL( false, file.IsReadable() ); } void testIsWritable_ReturnsTrue_PCM_WithReasonableHeader() { CLAM::AudioFileTarget file; CLAM::AudioFileHeader header; header.AddAll(); header.UpdateData(); header.SetChannels( 1 ); header.SetSampleRate( 22050 ); header.SetFormat( CLAM::EAudioFileFormat::eWAV ); header.SetEncoding( CLAM::EAudioFileEncoding::ePCM_24 ); header.SetEndianess( CLAM::EAudioFileEndianess::eDefault ); file.CreateNew( "NewFile.wav", header ); CPPUNIT_ASSERT_EQUAL( true, file.IsWritable() ); } void testIsWritable_ReturnsFalse_PCM_TooManyChannels() { CLAM::AudioFileTarget file; CLAM::AudioFileHeader header; header.AddAll(); header.UpdateData(); header.SetChannels( 291 ); header.SetSampleRate( 22050 ); header.SetFormat( CLAM::EAudioFileFormat::eWAV ); header.SetEncoding( CLAM::EAudioFileEncoding::ePCM_24 ); header.SetEndianess( CLAM::EAudioFileEndianess::eDefault ); file.CreateNew( "NewFile.wav", header ); CPPUNIT_ASSERT_EQUAL( false, file.IsWritable() ); } void testIsWritable_ReturnsFalse_PCM_TooFewChannels() { CLAM::AudioFileTarget file; CLAM::AudioFileHeader header; header.AddAll(); header.UpdateData(); header.SetChannels( 0 ); header.SetSampleRate( 22050 ); header.SetFormat( CLAM::EAudioFileFormat::eWAV ); header.SetEncoding( CLAM::EAudioFileEncoding::ePCM_24 ); header.SetEndianess( CLAM::EAudioFileEndianess::eDefault ); file.CreateNew( "NewFile.wav", header ); CPPUNIT_ASSERT_EQUAL( false, file.IsWritable() ); } void testOpenExisting_FileExists_and_Is_PCM() { CLAM::AudioFileSource file; file.OpenExisting( mPathToTestData + std::string("Elvis.wav") ); CPPUNIT_ASSERT_EQUAL( std::string("PCM"), file.GetCodec().GetString() ); } void testOpenExisting_FileExists_and_Is_OggVorbis() { CLAM::AudioFileSource file; file.OpenExisting( mPathToTestData + std::string( "Elvis.ogg" ) ); CPPUNIT_ASSERT_EQUAL( std::string("Ogg/Vorbis"), file.GetCodec().GetString() ); } void testOpenExisting_FileDoesNotExist_UnrecognizedFormat() { CLAM::AudioFileSource file; file.OpenExisting( mPathToTestData + std::string("nikora") ); CPPUNIT_ASSERT_EQUAL( std::string( "Unknown" ), file.GetCodec().GetString() ); } void testGetHeader_HeaderIsRight_PCM() { CLAM::AudioFileSource file; file.OpenExisting( mPathToTestData + std::string( "Elvis.wav" ) ); const CLAM::AudioFileHeader& header = file.GetHeader(); CPPUNIT_ASSERT_EQUAL( int(133888), int(header.GetSamples()) ); CPPUNIT_ASSERT_EQUAL( int(22050), int(header.GetSampleRate()) ); CPPUNIT_ASSERT_EQUAL( 1, header.GetChannels() ); CPPUNIT_ASSERT_EQUAL( int(6072.02), int(header.GetLength()) ); CPPUNIT_ASSERT_EQUAL( std::string("WAV"), header.GetFormat().GetString() ); CPPUNIT_ASSERT_EQUAL( std::string("signed 16-bit"), header.GetEncoding().GetString() ); CPPUNIT_ASSERT_EQUAL( std::string("Format Default"), header.GetEndianess().GetString() ); } void testGetHeader_HeaderIsRight_OggVorbis() { CLAM::AudioFileSource file; file.OpenExisting( mPathToTestData + std::string( "Elvis.ogg" ) ); const CLAM::AudioFileHeader& header = file.GetHeader(); CPPUNIT_ASSERT_EQUAL( int(22050.), int(header.GetSampleRate()) ); CPPUNIT_ASSERT_EQUAL( 1, header.GetChannels() ); CPPUNIT_ASSERT_EQUAL( int(5427), int(header.GetLength()) ); CPPUNIT_ASSERT_EQUAL( std::string( "VorbisMk1" ), header.GetFormat().GetString() ); CPPUNIT_ASSERT_EQUAL( std::string( "Format Default" ), header.GetEncoding().GetString() ); CPPUNIT_ASSERT_EQUAL( std::string( "Format Default" ), header.GetEndianess().GetString() ); } void testGetHeader_NoHeaderWhenFileIsUnreadable() { CLAM::AudioFileSource file; file.OpenExisting( "momonga" ); const CLAM::AudioFileHeader& header = file.GetHeader(); CPPUNIT_ASSERT_EQUAL( false, header.HasSampleRate() ); } void testGetHeader_NoHeaderWhenFileIsUnreadable_AfterOneSuccessful() { CLAM::AudioFileSource file; file.OpenExisting( mPathToTestData + std::string( "Elvis.wav" ) ); file.OpenExisting( "Momonga" ); const CLAM::AudioFileHeader& header = file.GetHeader(); CPPUNIT_ASSERT_EQUAL( false, header.HasSampleRate() ); } void testCreateNew_UserDefinesHeaderForWriting_PCM_RightCodecIsDeduced() { CLAM::AudioFileTarget file; CLAM::AudioFileHeader fileHeader; fileHeader.AddAll(); fileHeader.UpdateData(); fileHeader.SetSampleRate(44100.); fileHeader.SetChannels( 2 ); fileHeader.SetFormat( CLAM::EAudioFileFormat( "WAV" ) ); fileHeader.SetEncoding( CLAM::EAudioFileEncoding( "signed 24-bit" ) ); fileHeader.SetEndianess( CLAM::EAudioFileEndianess( "Format Default" ) ); file.CreateNew( "newFile.wav", fileHeader ); CPPUNIT_ASSERT_EQUAL( std::string( "PCM" ), file.GetCodec().GetString() ); } void testCreateNew_UserDefinesHeaderForWriting_Ogg_RightCodecIsDeduced() { CLAM::AudioFileTarget file; CLAM::AudioFileHeader fileHeader; fileHeader.AddAll(); fileHeader.UpdateData(); fileHeader.SetSampleRate(44100.); fileHeader.SetChannels( 2 ); fileHeader.SetFormat( CLAM::EAudioFileFormat( "VorbisMk1" ) ); fileHeader.SetEncoding( CLAM::EAudioFileEncoding( "Format Default" ) ); fileHeader.SetEndianess( CLAM::EAudioFileEndianess( "Format Default" ) ); file.CreateNew( "newFile.wav", fileHeader ); CPPUNIT_ASSERT_EQUAL( std::string( "Ogg/Vorbis" ), file.GetCodec().GetString() ); } void testCreateNew_WithoutSampleRate_Fails() { CLAM::AudioFileTarget file; CLAM::AudioFileHeader fileHeader; fileHeader.AddChannels(); fileHeader.AddFormat(); fileHeader.AddEncoding(); fileHeader.AddEndianess(); fileHeader.UpdateData(); fileHeader.SetChannels( 2 ); fileHeader.SetFormat( CLAM::EAudioFileFormat( "VorbisMk1" ) ); fileHeader.SetEncoding( CLAM::EAudioFileEncoding( "Format Default" ) ); fileHeader.SetEndianess( CLAM::EAudioFileEndianess( "Format Default" ) ); CPPUNIT_ASSERT_EQUAL( false, file.CreateNew( std::string( "newFile.wav" ), fileHeader )); } void testCreateNew_WithoutChannels_IsOK() { CLAM::AudioFileTarget file; CLAM::AudioFileHeader fileHeader; fileHeader.AddSampleRate(); fileHeader.AddFormat(); fileHeader.AddEncoding(); fileHeader.AddEndianess(); fileHeader.UpdateData(); fileHeader.SetFormat( CLAM::EAudioFileFormat( "VorbisMk1" ) ); fileHeader.SetEncoding( CLAM::EAudioFileEncoding( "Format Default" ) ); fileHeader.SetEndianess( CLAM::EAudioFileEndianess( "Format Default" ) ); CPPUNIT_ASSERT_EQUAL( true, file.CreateNew("newFile.wav", fileHeader) ); } void testCreateNew_WithoutFormat_Fails() { CLAM::AudioFileTarget file; CLAM::AudioFileHeader fileHeader; fileHeader.AddSampleRate(); fileHeader.AddChannels(); fileHeader.AddEncoding(); fileHeader.AddEndianess(); fileHeader.UpdateData(); CPPUNIT_ASSERT_EQUAL( false, file.CreateNew("newFile.wav", fileHeader) ); } void testCreateNew_SetValues_WAV() { CLAM::AudioFileTarget file; CLAM::AudioFileHeader fileHeader; fileHeader.SetValues( 44100., 2, "WAV" ); CPPUNIT_ASSERT_EQUAL( true, file.CreateNew("newFile.wav", fileHeader) ); } void testCreateNew_SetValues_AIFF() { CLAM::AudioFileTarget file; CLAM::AudioFileHeader fileHeader; fileHeader.SetValues( 44100., 2, "AIFF" ); CPPUNIT_ASSERT_EQUAL( true, file.CreateNew("newFile.wav", fileHeader) ); } void testCreateNew_SetValues_OggVorbis() { CLAM::AudioFileTarget file; CLAM::AudioFileHeader fileHeader; fileHeader.SetValues( 44100., 2, "VorbisMk1" ); CPPUNIT_ASSERT_EQUAL( true, file.CreateNew("newFile.wav", fileHeader) ); } void testCreateNew_SetValues_WAV_AreWritable() { CLAM::AudioFileTarget file; CLAM::AudioFileHeader fileHeader; fileHeader.SetValues( 44100., 2, "WAV" ); file.CreateNew( "newFile.wav", fileHeader ); CPPUNIT_ASSERT_EQUAL( true, file.IsWritable() ); } void testCreateNew_SetValues_AIFF_AreWritable() { CLAM::AudioFileTarget file; CLAM::AudioFileHeader fileHeader; fileHeader.SetValues( 44100., 2, "AIFF" ); file.CreateNew( "newFile.aiff", fileHeader ); CPPUNIT_ASSERT_EQUAL( true, file.IsWritable() ); } void testCreateNew_SetValues_OggVorbis_AreWritable() { CLAM::AudioFileTarget file; CLAM::AudioFileHeader fileHeader; fileHeader.SetValues( 44100., 2, "VorbisMk1" ); file.CreateNew( "newFile.ogg", fileHeader ); CPPUNIT_ASSERT_EQUAL( true, file.IsWritable() ); } void testOpenExisting_FileExists_and_Is_Mpeg() { CLAM::AudioFileSource file; file.OpenExisting( mPathToTestData + std::string( "trumpet.mp3" ) ); CPPUNIT_ASSERT_EQUAL( std::string("Mpeg Audio"), file.GetCodec().GetString() ); } void testOpenExisting_FileExists_NotSpurious_Mpeg() { CLAM::AudioFileSource file; file.OpenExisting( mPathToTestData + std::string( "ElvisStereo.wav" ) ); CPPUNIT_ASSERT( std::string("Mpeg Audio") != file.GetCodec().GetString() ); } void testGetHeader_HeaderIsRight_Mpeg() { CLAM::AudioFileSource file; file.OpenExisting( mPathToTestData + std::string( "trumpet.mp3" ) ); const CLAM::AudioFileHeader& header = file.GetHeader(); CPPUNIT_ASSERT_EQUAL( int(22050), (int)header.GetSampleRate() ); CPPUNIT_ASSERT_EQUAL( int(1), (int)header.GetChannels() ); CPPUNIT_ASSERT_EQUAL( int(2430), (int)header.GetLength() ); CPPUNIT_ASSERT_EQUAL( std::string("Mpeg Audio Layer 3"), header.GetFormat().GetString() ); CPPUNIT_ASSERT_EQUAL( std::string("Format Default"), header.GetEncoding().GetString() ); CPPUNIT_ASSERT_EQUAL( std::string("Format Default"), header.GetEndianess().GetString() ); } void testTextDescriptorsExtraction_From_OggVorbis() { CLAM::AudioFileSource file; file.OpenExisting( mPathToTestData + std::string( "Elvis.ogg" ) ); const CLAM::AudioTextDescriptors& txtDesc = file.GetTextDescriptors(); CPPUNIT_ASSERT_EQUAL( CLAM::Text("Elvis Presley"), txtDesc.GetArtist() ); CPPUNIT_ASSERT_EQUAL( CLAM::Text("My Love Complete"), txtDesc.GetTitle() ); CPPUNIT_ASSERT_EQUAL( CLAM::Text("Unknown"), txtDesc.GetAlbum() ); CPPUNIT_ASSERT_EQUAL( CLAM::Text("1"), txtDesc.GetTrackNumber() ); } void testTextDescriptorsExtraction_From_Mpeg() { CLAM::AudioFileSource file; file.OpenExisting( mPathToTestData + CLAM::Text( "trumpet.mp3" ) ); const CLAM::AudioTextDescriptors& txtDesc = file.GetTextDescriptors(); CPPUNIT_ASSERT_EQUAL( CLAM::Text("The Trumpeteers"), txtDesc.GetArtist() ); CPPUNIT_ASSERT_EQUAL( CLAM::Text("A Trumpet"), txtDesc.GetTitle() ); CPPUNIT_ASSERT_EQUAL( CLAM::Text("Trumpets, Trumpets, Trumpets"), txtDesc.GetAlbum() ); CPPUNIT_ASSERT_EQUAL( CLAM::Text("1"), txtDesc.GetTrackNumber() ); } }; } clam-1.4.0/test/UnitTests/FlowControlTests/0000755000000000000000000000000011344231437017344 5ustar rootrootclam-1.4.0/test/UnitTests/FlowControlTests/TestsStlVector.cxx0000644000000000000000000000462310610720021023030 0ustar rootroot #include #include #include //#include VC7.1 compiler chokes on that. namespace CLAMTest { class TestsStlVector ; CPPUNIT_TEST_SUITE_REGISTRATION( TestsStlVector ); class TestsStlVector : public CppUnit::TestFixture { public: CPPUNIT_TEST_SUITE( TestsStlVector ); CPPUNIT_TEST( testReserve ); CPPUNIT_TEST( testAt ); CPPUNIT_TEST( testResize_beforeReserve ); CPPUNIT_TEST( testList_isCircularWithPhantomElement ); CPPUNIT_TEST( testDeque_elementsNotInContiguousSpace ); CPPUNIT_TEST( testVectorInsertInTheMiddle ); CPPUNIT_TEST_SUITE_END(); void testReserve() { std::vector vector; vector.reserve(5); CPPUNIT_ASSERT(0 == vector.size()); } void testAt() { std::vector vector; vector.reserve(5); try { vector.at(1); // en canvi l'operator[] no fa comprovacions CPPUNIT_FAIL("hauria d'haver llençat exception"); //funciona tant en debug com en release } catch (std::exception&) { } } void testResize_beforeReserve() { std::vector vector; vector.resize(5); CPPUNIT_ASSERT(5 == vector.size()); CPPUNIT_ASSERT(5 <= vector.capacity()); vector.at(4)=1; CPPUNIT_ASSERT(1==vector.at(4)); } void testList_isCircularWithPhantomElement() { typedef std::list List; List list; list.push_back(0); list.push_back(1); list.push_back(2); List::iterator it=list.begin(); for(int i=0; i<3; i++,it++); CPPUNIT_ASSERT(it==list.end()); it++; // we are out of range: let's see that magically we're in the beginning CPPUNIT_ASSERT(it!=list.end()); (*it)=66; CPPUNIT_ASSERT(66==*list.begin()); } void testDeque_elementsNotInContiguousSpace() { /* VC7 Compiler problem with deque std::deque deque; deque.push_back(1); deque.push_back(2); deque.push_back(3); deque.push_back(4); deque.push_back(5); deque.push_front(0); CPPUNIT_ASSERT_EQUAL(5, deque.at(5)); CPPUNIT_ASSERT(5 != *(&(deque.at(0))+5) ); */ } void testVectorInsertInTheMiddle() { std::vector buff; buff.resize(8); buff[0]='h'; buff[1]='e'; buff[2]='o'; buff[3]=' '; buff[4]='a'; buff[5]='l'; buff[6]='l'; buff[7]='\0'; std::vector::iterator it = buff.begin(); it += 2; buff.insert(it, 2, 'l'); CPPUNIT_ASSERT_EQUAL( 10, int(buff.size()) ); CPPUNIT_ASSERT_EQUAL( std::string("hello all"), std::string((char *)(&buff[0])) ); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/FlowControlTests/TestsPortsRegionsInteraction.cxx0000644000000000000000000004260611337304343025760 0ustar rootroot#include #include "InPort.hxx" // CLAM #include "OutPort.hxx" // CLAM #include "InPortPublisher.hxx" // CLAM #include "OutPortPublisher.hxx" // CLAM #include "AudioInPortPublisher.hxx" // CLAM #include "AudioOutPortPublisher.hxx" // CLAM #include "AudioInPort.hxx" // CLAM #include "AudioOutPort.hxx" // CLAM namespace CLAMTest { class TestsPortsRegionsInteraction ; CPPUNIT_TEST_SUITE_REGISTRATION( TestsPortsRegionsInteraction ); class TestsPortsRegionsInteraction : public CppUnit::TestFixture { public: CPPUNIT_TEST_SUITE( TestsPortsRegionsInteraction ); CPPUNIT_TEST( testOutPortConnectToIn_usingBaseClass ); CPPUNIT_TEST( testOutPortConnect ); CPPUNIT_TEST( testOutPortConnect_whenPortsAlreadyConnected ); CPPUNIT_TEST( testOutPortConnect_whenInPortAlreadyConnectedToAnotherOutPort ); CPPUNIT_TEST( testOutPortConnect_whenMoreThanOneInPort ); CPPUNIT_TEST( testOutPortConnectNotifiesInPort ); CPPUNIT_TEST( testOutPortDisconnect_whenPortsAreConnected ); CPPUNIT_TEST( testOutPortDisconnect_whenPortsAreConnected_usingBaseClass ); CPPUNIT_TEST( testOutPortDisconnect_whenPortsAreNotConnected_throwsException ); CPPUNIT_TEST( testOutPortDisconnect_whenMoreThanOneInPort ); CPPUNIT_TEST( testOutPortDisconnectNotifiesInPort ); CPPUNIT_TEST( testPortChangeSizeResizesRegion ); CPPUNIT_TEST( testProduceAndConsume ); CPPUNIT_TEST( testProduceAndConsume_whenMoreThanOneInPort ); CPPUNIT_TEST( testOutPortGetConnectedInPorts_whenOneInPort ); CPPUNIT_TEST( testOutPortGetConnectedInPorts_whenMoreThanOneInPort ); CPPUNIT_TEST( testInPortGetConnectedOutPort ); CPPUNIT_TEST( testOutPortDisconnectFromAll ); CPPUNIT_TEST( testOutPort_IsConnectableTo_WhenInPortIsTheSameType ); CPPUNIT_TEST( testOutPort_IsConnectableTo_WhenInPortIsDifferentType ); CPPUNIT_TEST( testConnectedPortsDestructors_whenInDeletedBefore ); CPPUNIT_TEST( testInPortPublisher_PublishInPort_withIncorrectInPort ); CPPUNIT_TEST( testInPortPublisher_PublishInPort_withProperInPort ); CPPUNIT_TEST( testOutPortPublisher_PublishOutPort_withIncorrectOutPort ); CPPUNIT_TEST( testOutPortPublisher_destructor ); CPPUNIT_TEST( testAudioOutPortPublisher_beginDeletingPublished ); CPPUNIT_TEST( testOutPortPublisher_PublishOutPort_withProperOutPort ); CPPUNIT_TEST( testInPortPublisher_PublishInPort_withSomeInPorts ); CPPUNIT_TEST( testOutPort_GetConnectedInPorts_whenConnectedToInPortPublisher ); CPPUNIT_TEST( testOutPortPublisher_SetSize_assertsWhenDoesntPublishAnyPort ); CPPUNIT_TEST( testAudioOutPortPublisher_SetSize_assertsWhenDoesntPublishAnyPort ); CPPUNIT_TEST( testAudioOutPort_DefaultSize ); CPPUNIT_TEST( testAudioInPort_DefaultSize ); CPPUNIT_TEST( testOutPort_IsPhysicallyConnectedToIn_withOneInPort ); CPPUNIT_TEST( testGetLastWrittenData_fillsWithCorrectData ); // delete sequence tests: CPPUNIT_TEST( testOutPort_deleteSequence_Out_In ); CPPUNIT_TEST( testPort_deleteSequence_In_Out ); CPPUNIT_TEST( testPortPublisher_deleteSequence_In_InPub_Out ); CPPUNIT_TEST( testPortPublisher_deleteSequence_Out_InPub_In ); CPPUNIT_TEST( testAudioInPortPublisher_deleteSequence_Out_InPub_In ); CPPUNIT_TEST( testOutPortPublisher_getsVisuallyAttached ); CPPUNIT_TEST( testOutPortPublisher_getsDisconnected ); CPPUNIT_TEST_SUITE_END(); public: void setUp() { } void tearDown() { } void testOutPortConnectToIn_usingBaseClass() { CLAM::OutPort out; CLAM::InPort in; CLAM::OutPortBase& outBase = out; CLAM::InPortBase& inBase = in; outBase.ConnectToIn(inBase); CPPUNIT_ASSERT_EQUAL( true, outBase.IsVisuallyConnectedTo(inBase) ); } void testOutPortConnect() { CLAM::OutPort out; CLAM::InPort in; out.ConnectToIn(in); //TODO check that stream has been initialized (as soon as is implemented) CPPUNIT_ASSERT_EQUAL( true, out.IsVisuallyConnectedTo( in ) ); } void testOutPortConnect_whenMoreThanOneInPort() { CLAM::OutPort out; CLAM::InPort in1, in2; out.ConnectToIn(in1); out.ConnectToIn(in2); CPPUNIT_ASSERT_EQUAL( true, out.IsVisuallyConnectedTo(in1) ); CPPUNIT_ASSERT_EQUAL( true, out.IsVisuallyConnectedTo(in2) ); } void testOutPortConnect_whenPortsAlreadyConnected() { CLAM::OutPort out; CLAM::InPort in; out.ConnectToIn(in); try { out.ConnectToIn(in); CPPUNIT_FAIL("exception should be thrown"); } catch( CLAM::ErrAssertionFailed& ) { } } void testOutPortConnect_whenInPortAlreadyConnectedToAnotherOutPort() { CLAM::OutPort out, out2; CLAM::InPort in; out.ConnectToIn(in); try { out2.ConnectToIn(in); CPPUNIT_FAIL("exception should be thrown"); } catch( CLAM::ErrAssertionFailed& ) { } } void testOutPortConnectNotifiesInPort() { CLAM::OutPort out; CLAM::InPort in; CPPUNIT_ASSERT( 0 == in.GetVisuallyConnectedOutPort() ); out.ConnectToConcreteIn(in); CPPUNIT_ASSERT( &out == in.GetVisuallyConnectedOutPort() ); } void testOutPortDisconnect_whenPortsAreConnected() { CLAM::OutPort out; CLAM::InPort in; out.ConnectToConcreteIn(in); out.DisconnectFromConcreteIn( in ); CPPUNIT_ASSERT(0 == in.GetVisuallyConnectedOutPort() ); CPPUNIT_ASSERT( out.BeginVisuallyConnectedInPorts() == out.EndVisuallyConnectedInPorts() ); } void testOutPortDisconnect_whenPortsAreConnected_usingBaseClass() { CLAM::OutPort out; CLAM::InPort in; CLAM::OutPortBase& outBase = out; CLAM::InPortBase& inBase = in; outBase.ConnectToIn(inBase); outBase.DisconnectFromIn(inBase); CPPUNIT_ASSERT_EQUAL( false, outBase.IsVisuallyConnectedTo(inBase) ); } void testOutPortDisconnect_whenPortsAreNotConnected_throwsException() { CLAM::OutPort out; CLAM::InPort in; try { out.DisconnectFromConcreteIn( in ); CPPUNIT_FAIL("exception should be thrown"); } catch( CLAM::ErrAssertionFailed& ) { } } void testOutPortDisconnect_whenMoreThanOneInPort() { CLAM::OutPort out; CLAM::InPort in1, in2, in3; out.ConnectToConcreteIn(in1); out.ConnectToConcreteIn(in2); out.ConnectToConcreteIn(in3); out.DisconnectFromConcreteIn(in2); CPPUNIT_ASSERT_EQUAL( false, out.IsVisuallyConnectedTo(in2) ); } void testOutPortDisconnectNotifiesInPort() { CLAM::OutPort out; CLAM::InPort in; out.ConnectToConcreteIn(in); out.DisconnectFromConcreteIn(in); CPPUNIT_ASSERT( 0 == in.GetVisuallyConnectedOutPort() ); } void testPortChangeSizeResizesRegion() { CLAM::OutPort out; int newSize = 5; out.SetSize(5); CPPUNIT_ASSERT_EQUAL( newSize, out.GetSize() ); } void testProduceAndConsume() { CLAM::OutPort out; CLAM::InPort in; int data = 4; out.ConnectToIn(in); out.GetData() = 4; out.Produce(); CPPUNIT_ASSERT_EQUAL( data, in.GetData() ); } void testProduceAndConsume_whenMoreThanOneInPort() { CLAM::OutPort out; CLAM::InPort in1, in2, in3; int data1 = 1; int data2 = 2; int data3 = 3; out.ConnectToConcreteIn(in1); out.ConnectToConcreteIn(in2); out.ConnectToConcreteIn(in3); in1.SetSize(2); in3.SetSize(3); out.GetData() = data1; out.Produce(); out.GetData() = data2; out.Produce(); out.GetData() = data3; out.Produce(); CPPUNIT_ASSERT_EQUAL( data1, in1.GetData() ); CPPUNIT_ASSERT_EQUAL( data2, in1.GetData(1) ); CPPUNIT_ASSERT_EQUAL( data1, in2.GetData() ); CPPUNIT_ASSERT_EQUAL( data1, in3.GetData() ); CPPUNIT_ASSERT_EQUAL( data2, in3.GetData(1) ); CPPUNIT_ASSERT_EQUAL( data3, in3.GetData(2) ); } void testOutPortGetConnectedInPorts_whenOneInPort() { CLAM::OutPort out; CLAM::InPort in; out.ConnectToIn( in ); CLAM::OutPortBase::InPortsList::iterator it = out.BeginVisuallyConnectedInPorts(); CPPUNIT_ASSERT( it != out.EndVisuallyConnectedInPorts() ); CPPUNIT_ASSERT( *(it++) = &in ); CPPUNIT_ASSERT( it == out.EndVisuallyConnectedInPorts() ); } void testOutPortGetConnectedInPorts_whenMoreThanOneInPort() { CLAM::OutPort out; CLAM::InPort in1, in2, in3; out.ConnectToIn( in1 ); out.ConnectToIn( in2 ); out.ConnectToIn( in3 ); CLAM::OutPortBase::InPortsList::iterator it = out.BeginVisuallyConnectedInPorts(); CPPUNIT_ASSERT( it != out.EndVisuallyConnectedInPorts() ); CPPUNIT_ASSERT( *(it++) = &in1 ); CPPUNIT_ASSERT( *(it++) = &in2 ); CPPUNIT_ASSERT( *(it++) = &in3 ); CPPUNIT_ASSERT( it == out.EndVisuallyConnectedInPorts() ); } void testInPortGetConnectedOutPort() { CLAM::OutPort out; CLAM::InPort in1, in2; out.ConnectToIn( in1 ); out.ConnectToIn( in2 ); CPPUNIT_ASSERT( &out == in1.GetVisuallyConnectedOutPort() ); CPPUNIT_ASSERT( &out == in2.GetVisuallyConnectedOutPort() ); } void testOutPortDisconnectFromAll() { CLAM::OutPort out; CLAM::InPort in1, in2, in3; out.ConnectToIn( in1 ); out.ConnectToIn( in2 ); out.ConnectToIn( in3 ); out.DisconnectFromAll(); CPPUNIT_ASSERT( out.BeginVisuallyConnectedInPorts() == out.EndVisuallyConnectedInPorts() ); CPPUNIT_ASSERT( !in1.HasProcessing() ); CPPUNIT_ASSERT( !in2.HasProcessing() ); CPPUNIT_ASSERT( !in3.HasProcessing() ); } void testOutPort_IsConnectableTo_WhenInPortIsTheSameType() { CLAM::OutPort out; CLAM::InPort in; CLAM::OutPortBase & baseOutPort = out; CLAM::InPortBase & baseInPort = in; CPPUNIT_ASSERT_EQUAL( true, baseOutPort.IsConnectableTo(baseInPort) ); } void testOutPort_IsConnectableTo_WhenInPortIsDifferentType() { CLAM::OutPort out; CLAM::InPort in; CLAM::OutPortBase & baseOutPort = out; CLAM::InPortBase & baseInPort = in; CPPUNIT_ASSERT_EQUAL( false, baseOutPort.IsConnectableTo(baseInPort) ); } void testInPortPublisher_PublishInPort_withIncorrectInPort() { CLAM::InPort in; CLAM::InPortPublisher inPublisher; try { inPublisher.PublishInPort( in ); CPPUNIT_FAIL( "Assertion should fail" ); } catch( CLAM::ErrAssertionFailed & ) { } } void testConnectedPortsDestructors_whenInDeletedBefore() { CLAM::OutPort *out = new CLAM::OutPort(); CLAM::InPort *in = new CLAM::InPort(); CLAM::InPortPublisher *inPublisher = new CLAM::InPortPublisher(); inPublisher->PublishInPort( *in ); out->ConnectToIn(*inPublisher); delete inPublisher; delete out; } void testInPortPublisher_PublishInPort_withProperInPort() { CLAM::OutPort out;; CLAM::InPort in; CLAM::InPortPublisher inPublisher; inPublisher.PublishInPort( in ); int data = 4; out.ConnectToIn(inPublisher); out.GetData() = data; out.Produce(); CPPUNIT_ASSERT_EQUAL( data, in.GetData() ); } void testOutPortPublisher_PublishOutPort_withIncorrectOutPort() { CLAM::OutPort out; CLAM::OutPortPublisher outPublisher; try { outPublisher.PublishOutPort( out ); CPPUNIT_FAIL( "Assertion should fail" ); } catch( CLAM::ErrAssertionFailed & ) { } } void testOutPortPublisher_destructor() { CLAM::OutPort *out = new CLAM::OutPort ; CLAM::InPort *in = new CLAM::InPort; CLAM::OutPortPublisher *outPublisher = new CLAM::OutPortPublisher; outPublisher->PublishOutPort( *out ); outPublisher->ConnectToIn( *in ); delete outPublisher; delete in; delete out; } void testAudioOutPortPublisher_beginDeletingPublished() { CLAM::AudioOutPort *out = new CLAM::AudioOutPort; CLAM::AudioInPort *in = new CLAM::AudioInPort; CLAM::AudioOutPortPublisher *outPublisher = new CLAM::AudioOutPortPublisher; outPublisher->PublishOutPort( *out ); outPublisher->ConnectToIn( *in ); delete out; delete outPublisher; delete in; } void testOutPortPublisher_PublishOutPort_withProperOutPort() { CLAM::OutPort out; CLAM::InPort in; CLAM::OutPortPublisher outPublisher; outPublisher.PublishOutPort( out ); int data = 4; outPublisher.ConnectToIn(in); out.GetData() = data; CPPUNIT_ASSERT_EQUAL( data, outPublisher.GetData() ); out.Produce(); CPPUNIT_ASSERT_EQUAL( data, in.GetData() ); } void testInPortPublisher_PublishInPort_withSomeInPorts() { CLAM::OutPort out; CLAM::InPort in; CLAM::InPort in2; CLAM::InPort in3; CLAM::InPortPublisher inPublisher; inPublisher.PublishInPort( in ); inPublisher.PublishInPort( in2 ); inPublisher.PublishInPort( in3 ); int data = 4; out.ConnectToIn(inPublisher); out.GetData() = data; out.Produce(); CPPUNIT_ASSERT_EQUAL( data, in.GetData() ); CPPUNIT_ASSERT_EQUAL( data, in2.GetData() ); CPPUNIT_ASSERT_EQUAL( data, in3.GetData() ); } void testOutPort_GetConnectedInPorts_whenConnectedToInPortPublisher() { CLAM::OutPort out; CLAM::InPort in1, in2, in3; CLAM::InPortPublisher pubIn; pubIn.PublishInPort( in1 ); pubIn.PublishInPort( in2 ); pubIn.PublishInPort( in3 ); out.ConnectToIn( pubIn ); // let's check that the connected list of pubOut have a unique // entry (which is &pubIn) CLAM::OutPortBase::InPortsList::iterator it = out.BeginVisuallyConnectedInPorts(); CPPUNIT_ASSERT( it != out.EndVisuallyConnectedInPorts() ); CPPUNIT_ASSERT( *(it++) = &pubIn ); CPPUNIT_ASSERT( it == out.EndVisuallyConnectedInPorts() ); } void testOutPortPublisher_SetSize_assertsWhenDoesntPublishAnyPort() { CLAM::OutPortPublisher pubOut; try { pubOut.GetSize(); CPPUNIT_FAIL("as assertion was expected from OutPortPublisher::GetSize()"); } catch( CLAM::ErrAssertionFailed& ) { } try { pubOut.GetHop(); CPPUNIT_FAIL("as assertion was expected from OutPortPublisher::GetHop()"); } catch( CLAM::ErrAssertionFailed& ) { } } void testAudioOutPortPublisher_SetSize_assertsWhenDoesntPublishAnyPort() { CLAM::AudioOutPortPublisher pubOut; try { pubOut.GetSize(); CPPUNIT_FAIL("as assertion was expected from OutPortPublisher::GetSize()"); } catch( CLAM::ErrAssertionFailed& ) { } try { pubOut.GetHop(); CPPUNIT_FAIL("as assertion was expected from OutPortPublisher::GetHop()"); } catch( CLAM::ErrAssertionFailed& ) { } } void testAudioOutPort_DefaultSize() { CLAM::AudioOutPort out; CPPUNIT_ASSERT_EQUAL_MESSAGE("Size not expected", 512, out.GetSize() ); CPPUNIT_ASSERT_EQUAL_MESSAGE("Hop not expected", 512, out.GetHop() ); } void testAudioInPort_DefaultSize() { CLAM::AudioInPort in; CPPUNIT_ASSERT_EQUAL_MESSAGE("Size not expected", 512, in.GetSize() ); CPPUNIT_ASSERT_EQUAL_MESSAGE("Hop not exptected", 512, in.GetHop() ); } void testGetLastWrittenData_fillsWithCorrectData() { CLAM::OutPort out; int data = 5; out.GetData() = data; out.Produce(); int result = out.GetLastWrittenData(); CPPUNIT_ASSERT_EQUAL( data, result ); } void testOutPort_IsPhysicallyConnectedToIn_withOneInPort() { CLAM::OutPort out; CLAM::InPort inPublished, inDirect, inNotConnected; CLAM::InPortPublisher publisher; publisher.PublishInPort( inPublished ); out.ConnectToIn( publisher ); // so inPublished gets "physically" connected out.ConnectToIn( inDirect ); CPPUNIT_ASSERT( true==out.IsPhysicallyConnectedToIn(inDirect) ); CPPUNIT_ASSERT( true==out.IsPhysicallyConnectedToIn(inPublished) ); CPPUNIT_ASSERT( false==out.IsPhysicallyConnectedToIn(inNotConnected) ); } void testOutPort_deleteSequence_Out_In() { CLAM::InPort * in = new CLAM::InPort; CLAM::OutPort * out = new CLAM::OutPort; out->ConnectToIn( *in ); delete out; delete in; } void testPort_deleteSequence_In_Out() { CLAM::InPort * in = new CLAM::InPort; CLAM::OutPort * out = new CLAM::OutPort; out->ConnectToIn( *in ); delete in; delete out; } void testPortPublisher_deleteSequence_In_InPub_Out() { CLAM::OutPort out; CLAM::InPort *in1, *in2; CLAM::InPortPublisher *pubIn; in1 = new CLAM::InPort; in2 = new CLAM::InPort; pubIn = new CLAM::InPortPublisher; pubIn->PublishInPort( *in1 ); pubIn->PublishInPort( *in2 ); out.ConnectToIn( *pubIn ); delete in1; delete in2; delete pubIn; CLAM::OutPortBase::InPortsList::iterator it = out.BeginVisuallyConnectedInPorts(); CPPUNIT_ASSERT(it == out.EndVisuallyConnectedInPorts() ); } void testPortPublisher_deleteSequence_Out_InPub_In() { CLAM::OutPort *out = new CLAM::OutPort; CLAM::InPort *in = new CLAM::InPort; CLAM::InPortPublisher *pubIn = new CLAM::InPortPublisher; pubIn->PublishInPort( *in ); out->ConnectToIn( *pubIn ); delete out; CPPUNIT_ASSERT( 0 == pubIn->GetVisuallyConnectedOutPort() ); delete pubIn; delete in; } void testAudioInPortPublisher_deleteSequence_Out_InPub_In() { CLAM::AudioInPortPublisher *pub = new CLAM::AudioInPortPublisher; CLAM::AudioInPort *in = new CLAM::AudioInPort; CLAM::AudioOutPort *out = new CLAM::AudioOutPort; pub->PublishInPort( *in ); out->ConnectToIn( *pub ); delete out; delete pub; delete in; } void testOutPortPublisher_getsVisuallyAttached() { CLAM::AudioOutPortPublisher pub; CLAM::AudioOutPort out; CLAM::AudioInPort in; pub.PublishOutPort( out ); pub.ConnectToIn( in ); CLAM::OutPortBase *basePub = &pub; CPPUNIT_ASSERT( basePub == in.GetVisuallyConnectedOutPort() ); } void testOutPortPublisher_getsDisconnected() { CLAM::AudioOutPortPublisher pub; CLAM::AudioOutPort out; CLAM::AudioInPort in; pub.PublishOutPort( out ); pub.ConnectToIn( in ); in.Disconnect(); CPPUNIT_ASSERT( false == out.HasConnections() ); CPPUNIT_ASSERT( 0 == in.GetVisuallyConnectedOutPort() ); CPPUNIT_ASSERT( false == pub.HasConnections() ); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/FlowControlTests/TestsAudioPorts.cxx0000644000000000000000000001375610610720021023203 0ustar rootroot #include #include "AudioOutPort.hxx" // CLAM #include "AudioInPort.hxx" // CLAM #include "Audio.hxx" // CLAM #include "AudioOutPortPublisher.hxx" // CLAM #include "AudioInPortPublisher.hxx" // CLAM namespace CLAMTest { class TestsAudioPorts ; CPPUNIT_TEST_SUITE_REGISTRATION( TestsAudioPorts ); class TestsAudioPorts : public CppUnit::TestFixture { public: CPPUNIT_TEST_SUITE( TestsAudioPorts ); CPPUNIT_TEST( testCreateAudioOutPorts ); CPPUNIT_TEST( testRegionOfAudioOutPort_hasCorrectSize ); CPPUNIT_TEST( testAccessAudioOutPortDataReturnsAudioInsteadOfTData ); CPPUNIT_TEST( testAudioPortsProduceAndConsume_whenInPortHasEqualSizeOfOne ); CPPUNIT_TEST( testAudioPortsProduceAndConsume_whenInPortHasEqualSizeGreaterThanOne ); CPPUNIT_TEST( testAudioPortsProduceAndConsume_afterConsuming ); CPPUNIT_TEST( testAudioPortsProduceAndConsume_whenMoreThanOneReader ); CPPUNIT_TEST( testAudioPortsProduceAndConsume_whenDifferentSizes ); CPPUNIT_TEST( testAudioInPortPublisher_PublishInPort_withIncorrectInPort ); CPPUNIT_TEST( testAudioInPortPublisher_PublishInPort_withProperInPort ); CPPUNIT_TEST_SUITE_END(); void testCreateAudioOutPorts() { CLAM::AudioOutPort out; } void testRegionOfAudioOutPort_hasCorrectSize() { CLAM::AudioOutPort out; int frameSize = 64; out.SetSize( frameSize ); CPPUNIT_ASSERT_EQUAL( frameSize, out.GetSize() ); } void testAccessAudioOutPortDataReturnsAudioInsteadOfTData() { CLAM::AudioOutPort out; int frameSize = 64; out.SetSize( frameSize ); CLAM::Audio & myAudio = out.GetAudio(); } void testAudioPortsProduceAndConsume_whenInPortHasEqualSizeOfOne() { CLAM::AudioOutPort out; CLAM::AudioInPort in; int frameSize = 1; CLAM::TData data = 0.5; out.ConnectToConcreteIn(in); out.SetSize( frameSize ); in.SetSize( frameSize ); CLAM::Audio & toProduce = out.GetAudio(); toProduce.GetBuffer()[0] = data; out.Produce(); const CLAM::Audio & toConsume = in.GetAudio(); CPPUNIT_ASSERT_EQUAL( data, toConsume.GetBuffer()[0] ); } void testAudioPortsProduceAndConsume_whenInPortHasEqualSizeGreaterThanOne() { CLAM::AudioOutPort out; CLAM::AudioInPort in; int frameSize = 8; out.ConnectToConcreteIn(in); out.SetSize( frameSize ); out.SetHop( frameSize ); in.SetSize( frameSize ); CLAM::Audio & toProduce = out.GetAudio(); for(int i=0;i in; CLAM::AudioInPortPublisher inPublisher; try { inPublisher.PublishInPort( in ); CPPUNIT_FAIL( "Assertion should fail" ); } catch( CLAM::ErrAssertionFailed & ) { } } void testAudioInPortPublisher_PublishInPort_withProperInPort() { CLAM::AudioOutPort out; CLAM::AudioInPort in; CLAM::AudioInPortPublisher inPublisher; inPublisher.PublishInPort( in ); CLAM::TData data(4.0); out.ConnectToIn(inPublisher); out.GetAudio().GetBuffer()[0] = data; out.Produce(); CPPUNIT_ASSERT_EQUAL( data, in.GetAudio().GetBuffer()[0] ); } void testAudioOutPortPublisher_PublishOutPort_withProperOutPort() { CLAM::OutPort out; CLAM::AudioInPort in; CLAM::AudioOutPortPublisher outPublisher; outPublisher.PublishOutPort( out ); CLAM::TData data(4.0); outPublisher.ConnectToIn(in); out.GetData() = data; CPPUNIT_ASSERT_EQUAL( data, outPublisher.GetAudio().GetBuffer()[0] ); out.Produce(); CPPUNIT_ASSERT_EQUAL( data, in.GetAudio().GetBuffer()[0] ); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/FlowControlTests/TestsStlBasedStream.cxx0000644000000000000000000000170610610720021023757 0ustar rootroot#include #include "WritingRegion.hxx" // CLAM #include "ReadingRegion.hxx" // CLAM #include /** * Into this test suite goes all specific tests that only aply to STL based * stream and not to phantom-buffer stream */ //TODO it should be a template (stl container) class like TestsStream namespace CLAMTest { class TestsStlBasedStream ; CPPUNIT_TEST_SUITE_REGISTRATION( TestsStlBasedStream ); class TestsStlBasedStream : public CppUnit::TestFixture { public: CPPUNIT_TEST_SUITE( TestsStlBasedStream ); CPPUNIT_TEST( testStreamIncreasesSizeAfterProducing ); CPPUNIT_TEST_SUITE_END(); // tests of size of stream void testStreamIncreasesSizeAfterProducing() { CLAM::WritingRegion writer; writer.Size(5); writer.Hop(2); CPPUNIT_ASSERT_EQUAL(5, writer.LogicalStreamSize() ); writer.Produce(); CPPUNIT_ASSERT_EQUAL(7, writer.LogicalStreamSize() ); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/FlowControlTests/NetworkTest.cxx0000644000000000000000000007073111101735156022367 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "Processing.hxx" // CLAM #include "Network.hxx" // CLAM #include "BasicFlowControl.hxx" // CLAM #include #include "BaseLoggable.hxx" #include "InPort.hxx" // CLAM #include "OutPort.hxx" // CLAM #include "InControl.hxx" // CLAM #include "OutControl.hxx" // CLAM #include "DummyProcessingData.hxx" #include "Oscillator.hxx" // CLAM #include "AudioMultiplier.hxx" // CLAM #include "MonoAudioFileReader.hxx" // CLAM #include "AudioSink.hxx" // CLAM #include "AudioSource.hxx" // CLAM #include "AudioOut.hxx" // CLAM #include "AudioIn.hxx" // CLAM namespace CLAMTest { class NetworkTest; CPPUNIT_TEST_SUITE_REGISTRATION( NetworkTest ); class NetworkTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( NetworkTest ); CPPUNIT_TEST( testGetProcessing_WhenNoProcessings ); CPPUNIT_TEST( testGetProcessing_WhenProcessingAdded ); CPPUNIT_TEST( testGetProcessing_WithTwoProcessings ); CPPUNIT_TEST( testAddProcessing_UsingFactory ); CPPUNIT_TEST( testHasProcessing_WhenHasIt ); CPPUNIT_TEST( testHasProcessing_WhenHasntIt ); CPPUNIT_TEST( testDestructor_DeletesChildrenProcessings ); // InPort CPPUNIT_TEST( testGetInPortByCompleteName_WhenPortExist ); CPPUNIT_TEST( testGetInPortByCompleteName_WhenPortDoesntExist ); CPPUNIT_TEST( testGetInPortByCompleteName_WhenProcessingDoesntExist ); CPPUNIT_TEST( testGetInPortByCompleteName_WhithMalformedName_WithNoDot ); CPPUNIT_TEST( testGetInPortByCompleteName_WithThreeIdentifiers ); // OutPort CPPUNIT_TEST( testGetOutPortByCompleteName_WhenPortExist ); CPPUNIT_TEST( testGetOutPortByCompleteName_WhenPortDoesntExist ); CPPUNIT_TEST( testGetOutPortByCompleteName_WhenProcessingDoesntExist ); CPPUNIT_TEST( testGetOutPortByCompleteName_WhithMalformedName_WithNoDot ); CPPUNIT_TEST( testGetOutPortByCompleteName_WithThreeIdentifiers ); // InControl CPPUNIT_TEST( testGetInControlByCompleteName_WhenControlExist ); CPPUNIT_TEST( testGetInControlByCompleteName_WhenControlDoesntExist ); CPPUNIT_TEST( testGetInControlByCompleteName_WhenProcessingDoesntExist ); CPPUNIT_TEST( testGetInControlByCompleteName_WhithMalformedName_WithNoDot ); CPPUNIT_TEST( testGetInControlByCompleteName_WithThreeIdentifiers ); // OutControl CPPUNIT_TEST( testGetOutControlByCompleteName_WhenControlExist ); CPPUNIT_TEST( testGetOutControlByCompleteName_WhenControlDoesntExist ); CPPUNIT_TEST( testGetOutControlByCompleteName_WhenProcessingDoesntExist ); CPPUNIT_TEST( testGetOutControlByCompleteName_WhithMalformedName_WithNoDot ); CPPUNIT_TEST( testGetOutControlByCompleteName_WithThreeIdentifiers ); CPPUNIT_TEST( testConnectPorts_WhenConnectionIsValid ); CPPUNIT_TEST( testConnectPorts_WhenConnectionIsNotValid ); CPPUNIT_TEST( testRemovePortsConnection_WhenPortsAreNotConnected ); CPPUNIT_TEST( testRemovePortsConnection_WhenPortsAreConnected ); CPPUNIT_TEST( testRemoveProcessing_WhenHasIt ); CPPUNIT_TEST( testRemoveProcessing_WhenHasntIt ); CPPUNIT_TEST( testConnectControls_WhenConnectionIsValid ); CPPUNIT_TEST( testConnectControls_WhenConnectionIsNotValid ); CPPUNIT_TEST( testRemoveControlsConnection_WhenControlsAreNotConnected ); CPPUNIT_TEST( testRemoveControlsConnection_WhenControlsAreConnected ); // network state tests CPPUNIT_TEST( testStartNetworkStartsProcessings_WhenAreReady ); CPPUNIT_TEST( testStartNetworkDoesntStartProcessings_WhenAreNotReady ); CPPUNIT_TEST( testStopNetworkStopsProcessings_WhenAreRunning ); CPPUNIT_TEST( testStopNetworkDoesntStopProcessings_WhenAreNotRunning ); CPPUNIT_TEST( testIsEmpty_whenEmpty ); CPPUNIT_TEST( testIsEmpty_whenNotEmpty ); CPPUNIT_TEST( testHasMisconfiguredProcessings_whenAllConfigured ); CPPUNIT_TEST( testHasMisconfiguredProcessings_whenMisconfigured ); CPPUNIT_TEST( testHasSyncSource_whenEmpty ); CPPUNIT_TEST( testHasSyncSource_withExternalizer ); CPPUNIT_TEST( testSyncSourceProcessings ); CPPUNIT_TEST( testUseOfString_substr ); CPPUNIT_TEST_SUITE_END(); void testGetProcessing_WhenNoProcessings() { CLAM::Network net; try{ net.GetProcessing(std::string("not existing processing")); CPPUNIT_FAIL("Assert expected, but no exception was thrown"); } catch( CLAM::ErrAssertionFailed& ) {} } class DummyProcessing : public CLAM::Processing { CLAM::InPort mIn; const char* GetClassName() const { return "DummyProcessing"; } bool ConcreteConfigure( const CLAM::ProcessingConfig & cfg) { return true; } bool Do() { return false; } public: DummyProcessing() : mIn("Dummy In", this) { } }; void testGetProcessing_WhenProcessingAdded() { CLAM::Network net; CLAM::Processing* proc = new DummyProcessing; std::string name( "dummy-processing" ); net.AddProcessing( name, proc ); CPPUNIT_ASSERT_EQUAL ( proc, &net.GetProcessing( name ) ); } void testAddProcessing_UsingFactory() { CLAM::Network net; std::string name( "oscillator" ); std::string key( "Oscillator" ); net.AddProcessing( name, key ); CPPUNIT_ASSERT_EQUAL ( true , net.HasProcessing( name ) ); } void testGetProcessing_WithTwoProcessings() { CLAM::Network net; CLAM::Processing* proc = new DummyProcessing; std::string name1( "the first" ); net.AddProcessing( name1, proc ); CLAM::Processing* proc2 = new DummyProcessing; net.AddProcessing( std::string("the second"),proc2 ); CPPUNIT_ASSERT_EQUAL( proc, &net.GetProcessing( name1 ) ); } void testHasProcessing_WhenHasIt() { CLAM::Network net; std::string name("the name"); net.AddProcessing( name, new DummyProcessing ); CPPUNIT_ASSERT_EQUAL( true, net.HasProcessing( name ) ); } void testHasProcessing_WhenHasntIt() { CLAM::Network net; CPPUNIT_ASSERT_EQUAL( false, net.HasProcessing(std::string("non-existing") ) ); } class LoggableDummyProcessing : public DummyProcessing { BaseLoggable& mLog; public: LoggableDummyProcessing( BaseLoggable& log ) : mLog(log) {} ~LoggableDummyProcessing() { mLog.ToLog() << this << " deleted\n"; } }; void testDestructor_DeletesChildrenProcessings() { BaseLoggable log; LoggableDummyProcessing* proc1 = new LoggableDummyProcessing(log); LoggableDummyProcessing* proc2 = new LoggableDummyProcessing(log); CLAM::Network* net = new CLAM::Network; net->AddProcessing( std::string("first"), proc1 ); net->AddProcessing( std::string("second"), proc2 ); delete net; std::ostringstream expected; expected << proc1 << " deleted\n" << proc2 << " deleted\n"; CPPUNIT_ASSERT_EQUAL(expected.str(), log.GetLog() ); } // helper model-class-adapter class NetworkProtectedInterfacePublisher : public CLAM::Network { public: CLAM::InPortBase & GetInPortByCompleteName( const std::string& name ) { return Network::GetInPortByCompleteName( name ); } CLAM::OutPortBase & GetOutPortByCompleteName( const std::string& name ) { return Network::GetOutPortByCompleteName( name ); } CLAM::InControlBase & GetInControlByCompleteName( const std::string& name ) { return Network::GetInControlByCompleteName( name ); } CLAM::OutControlBase & GetOutControlByCompleteName( const std::string& name ) { return Network::GetOutControlByCompleteName( name ); } }; /////////////////////////////////////////// ////////// GetInPort testing /////////// /////////////////////////////////////////// void testGetInPortByCompleteName_WhenPortExist() { //set up NetworkProtectedInterfacePublisher net; DummyProcessing* theProc = new DummyProcessing; net.AddProcessing( "theOnlyProcessing", theProc ); CLAM::InPortBase * expectedInPort = new CLAM::InPort( std::string("theOnlyInPort"), theProc ); // exercice and test CPPUNIT_ASSERT_EQUAL( expectedInPort, &net.GetInPortByCompleteName( std::string("theOnlyProcessing.theOnlyInPort") ) ); } void testGetInPortByCompleteName_WhenPortDoesntExist() { //set up NetworkProtectedInterfacePublisher net; net.AddProcessing( "theOnlyProcessing", new DummyProcessing ); // exercice and test try { net.GetInPortByCompleteName( std::string("theOnlyProcessing.NonExistingPort") ); CPPUNIT_FAIL("Expected assert, but didn't happened"); } catch( CLAM::ErrAssertionFailed& expected) { CPPUNIT_ASSERT_EQUAL( std::string( "No in port named 'NonExistingPort'.\nTry with: 'Dummy In'"), std::string( expected.what() ) ); } } void testGetInPortByCompleteName_WhenProcessingDoesntExist() { //set up NetworkProtectedInterfacePublisher net; // exercice and test try { net.GetInPortByCompleteName( std::string("NonExistingProcessing.NonExistingPort") ); CPPUNIT_FAIL("Expected assert, but didn't happened"); } catch( CLAM::ErrAssertionFailed& expected) { CPPUNIT_ASSERT_EQUAL( std::string( "No processing in the network has the name 'NonExistingProcessing'." ), std::string( expected.what() ) ); } } void testGetInPortByCompleteName_WhithMalformedName_WithNoDot() { //set up NetworkProtectedInterfacePublisher net; // exercice and test try { net.GetInPortByCompleteName( std::string("TheNameShould_ContainADot") ); CPPUNIT_FAIL("Expected assert, but didn't happened"); } catch( CLAM::ErrAssertionFailed& expected) { CPPUNIT_ASSERT_EQUAL( std::string( "Malformed port/control name. It should be ProcessingName.[Port/Control]Name" ), std::string( expected.what() ) ); } } void testGetInPortByCompleteName_WithThreeIdentifiers() { //set up NetworkProtectedInterfacePublisher net; DummyProcessing* theProc = new DummyProcessing; net.AddProcessing( "theOnlyProcessing", theProc ); CLAM::InPortBase * expectedInPort = new CLAM::InPort( std::string("theOnlyInPort"), theProc ); // exercice and test CPPUNIT_ASSERT_EQUAL( expectedInPort, &net.GetInPortByCompleteName( std::string("nonExistingNetwork.theOnlyProcessing.theOnlyInPort") ) ); } /////////////////////////////////////////// ////////// GetOutPort testing ////////// /////////////////////////////////////////// void testGetOutPortByCompleteName_WhenPortExist() { //set up NetworkProtectedInterfacePublisher net; DummyProcessing* theProc = new DummyProcessing; net.AddProcessing( "theOnlyProcessing", theProc ); CLAM::OutPortBase * expectedOutPort = new CLAM::OutPort( std::string("theOnlyOutPort"), theProc ); // exercice and test CPPUNIT_ASSERT_EQUAL( expectedOutPort, &net.GetOutPortByCompleteName( std::string("theOnlyProcessing.theOnlyOutPort") ) ); } void testGetOutPortByCompleteName_WhenPortDoesntExist() { //set up NetworkProtectedInterfacePublisher net; net.AddProcessing( "theOnlyProcessing", new DummyProcessing ); // exercice and test try { net.GetOutPortByCompleteName( std::string("theOnlyProcessing.NonExistingPort") ); CPPUNIT_FAIL("Expected assert, but didn't happened"); } catch( CLAM::ErrAssertionFailed& expected) { CPPUNIT_ASSERT_EQUAL( std::string( "No out port named 'NonExistingPort'.\nTry with: "), std::string( expected.what() ) ); } } void testGetOutPortByCompleteName_WhenProcessingDoesntExist() { //set up NetworkProtectedInterfacePublisher net; // exercice and test try { net.GetOutPortByCompleteName( std::string("NonExistingProcessing.NonExistingPort") ); CPPUNIT_FAIL("Expected assert, but didn't happened"); } catch( CLAM::ErrAssertionFailed& expected) { CPPUNIT_ASSERT_EQUAL( std::string( "No processing in the network has the name 'NonExistingProcessing'." ), std::string( expected.what() ) ); } } void testGetOutPortByCompleteName_WhithMalformedName_WithNoDot() { //set up NetworkProtectedInterfacePublisher net; // exercice and test try { net.GetOutPortByCompleteName( std::string("TheNameShould_ContainADot") ); CPPUNIT_FAIL("Expected assert, but didn't happened"); } catch( CLAM::ErrAssertionFailed& expected) { CPPUNIT_ASSERT_EQUAL( std::string( "Malformed port/control name. It should be ProcessingName.[Port/Control]Name" ), std::string( expected.what() ) ); } } void testGetOutPortByCompleteName_WithThreeIdentifiers() { //set up NetworkProtectedInterfacePublisher net; DummyProcessing* theProc = new DummyProcessing; net.AddProcessing( "theOnlyProcessing", theProc ); CLAM::OutPortBase * expectedOutPort = new CLAM::OutPort( std::string("theOnlyOutPort"), theProc ); // exercice and test CPPUNIT_ASSERT_EQUAL( expectedOutPort, &net.GetOutPortByCompleteName( std::string("nonExistingNetwork.theOnlyProcessing.theOnlyOutPort") ) ); } /////////////////////////////////////////// ////////// GetInControl testing /////////// /////////////////////////////////////////// void testGetInControlByCompleteName_WhenControlExist() { //set up NetworkProtectedInterfacePublisher net; DummyProcessing* theProc = new DummyProcessing; net.AddProcessing( "theOnlyProcessing", theProc ); CLAM::InControlBase * expectedInControl = new CLAM::FloatInControl( std::string("theOnlyInControl"), theProc ); // exercice and test CPPUNIT_ASSERT_EQUAL( expectedInControl, &net.GetInControlByCompleteName( std::string("theOnlyProcessing.theOnlyInControl") ) ); // tear down delete expectedInControl; } void testGetInControlByCompleteName_WhenControlDoesntExist() { //set up NetworkProtectedInterfacePublisher net; net.AddProcessing( "theOnlyProcessing", new DummyProcessing ); // exercice and test try { net.GetInControlByCompleteName( std::string("theOnlyProcessing.NonExistingControl") ); CPPUNIT_FAIL("Expected assert, but didn't happened"); } catch( CLAM::ErrAssertionFailed& expected) { CPPUNIT_ASSERT_EQUAL( std::string( "No in control named 'NonExistingControl'.\nTry with: " ), std::string( expected.what() ) ); } } void testGetInControlByCompleteName_WhenProcessingDoesntExist() { //set up NetworkProtectedInterfacePublisher net; // exercice and test try { net.GetInControlByCompleteName( std::string("NonExistingProcessing.NonExistingControl") ); CPPUNIT_FAIL("Expected assert, but didn't happened"); } catch( CLAM::ErrAssertionFailed& expected) { CPPUNIT_ASSERT_EQUAL( std::string( "No processing in the network has the name 'NonExistingProcessing'." ), std::string( expected.what() ) ); } } void testGetInControlByCompleteName_WhithMalformedName_WithNoDot() { //set up NetworkProtectedInterfacePublisher net; // exercice and test try { net.GetInControlByCompleteName( std::string("TheNameShould_ContainADot") ); CPPUNIT_FAIL("Expected assert, but didn't happened"); } catch( CLAM::ErrAssertionFailed& expected) { CPPUNIT_ASSERT_EQUAL( std::string( "Malformed port/control name. It should be ProcessingName.[Port/Control]Name" ), std::string( expected.what() ) ); } } void testGetInControlByCompleteName_WithThreeIdentifiers() { //set up NetworkProtectedInterfacePublisher net; DummyProcessing* theProc = new DummyProcessing; net.AddProcessing( "theOnlyProcessing", theProc ); CLAM::InControlBase* expectedInControl = new CLAM::FloatInControl( std::string("theOnlyInControl"), theProc ); // exercice and test CPPUNIT_ASSERT_EQUAL( expectedInControl, &net.GetInControlByCompleteName( std::string("nonExistingNetwork.theOnlyProcessing.theOnlyInControl") ) ); // tear down delete expectedInControl; } /////////////////////////////////////////// ////////// GetOutControl testing /////////// /////////////////////////////////////////// void testGetOutControlByCompleteName_WhenControlExist() { //set up NetworkProtectedInterfacePublisher net; DummyProcessing* theProc = new DummyProcessing; net.AddProcessing( "theOnlyProcessing", theProc ); CLAM::OutControlBase* expectedOutControl = new CLAM::FloatOutControl( std::string("theOnlyOutControl"), theProc ); // exercice and test CPPUNIT_ASSERT_EQUAL( expectedOutControl, &net.GetOutControlByCompleteName( std::string("theOnlyProcessing.theOnlyOutControl") ) ); // tear down delete expectedOutControl; } void testGetOutControlByCompleteName_WhenControlDoesntExist() { //set up NetworkProtectedInterfacePublisher net; net.AddProcessing( "theOnlyProcessing", new DummyProcessing ); // exercice and test try { net.GetOutControlByCompleteName( std::string("theOnlyProcessing.NonExistingControl") ); CPPUNIT_FAIL("Expected assert, but didn't happened"); } catch( CLAM::ErrAssertionFailed& expected) { CPPUNIT_ASSERT_EQUAL( std::string( "No out control named 'NonExistingControl'.\nTry with: " ), std::string( expected.what() ) ); } } void testGetOutControlByCompleteName_WhenProcessingDoesntExist() { //set up NetworkProtectedInterfacePublisher net; // exercice and test try { net.GetOutControlByCompleteName( std::string("NonExistingProcessing.NonExistingControl") ); CPPUNIT_FAIL("Expected assert, but didn't happened"); } catch( CLAM::ErrAssertionFailed& expected) { CPPUNIT_ASSERT_EQUAL( std::string( "No processing in the network has the name 'NonExistingProcessing'." ), std::string( expected.what() ) ); } } void testGetOutControlByCompleteName_WhithMalformedName_WithNoDot() { //set up NetworkProtectedInterfacePublisher net; // exercice and test try { net.GetOutControlByCompleteName( std::string("TheNameShould_ContainADot") ); CPPUNIT_FAIL("Expected assert, but didn't happened"); } catch( CLAM::ErrAssertionFailed& expected) { CPPUNIT_ASSERT_EQUAL( std::string( "Malformed port/control name. It should be ProcessingName.[Port/Control]Name" ), std::string( expected.what() ) ); } } void testGetOutControlByCompleteName_WithThreeIdentifiers() { //set up NetworkProtectedInterfacePublisher net; DummyProcessing* theProc = new DummyProcessing; net.AddProcessing( "theOnlyProcessing", theProc ); CLAM::OutControlBase* expectedOutControl = new CLAM::FloatOutControl( std::string("theOnlyOutControl"), theProc ); // exercice and test CPPUNIT_ASSERT_EQUAL( expectedOutControl, &net.GetOutControlByCompleteName( std::string("nonExistingNetwork.theOnlyProcessing.theOnlyOutControl") ) ); // tear down delete expectedOutControl; } void testUseOfString_substr() { std::string today("today it rains"); CPPUNIT_ASSERT_EQUAL( std::string("it"), today.substr(6,2) ); } void testConnectPorts_WhenConnectionIsValid() { CLAM::Network net; DummyProcessing* firstProc = new DummyProcessing; DummyProcessing* secondProc = new DummyProcessing; net.AddProcessing( "first", firstProc ); net.AddProcessing( "second", secondProc ); CLAM::OutPortBase * outPortOfFirstProc = new CLAM::OutPort( std::string("outPortOfFirstProc"), firstProc ); CLAM::InPortBase * inPortOfSecondProc = new CLAM::InPort( std::string("inPortOfSecondProc"), secondProc ); net.ConnectPorts("first.outPortOfFirstProc","second.inPortOfSecondProc"); CPPUNIT_ASSERT_EQUAL( true, outPortOfFirstProc->IsVisuallyConnectedTo(*inPortOfSecondProc) ); } void testConnectPorts_WhenConnectionIsNotValid() { CLAM::Network net; DummyProcessing* firstProc = new DummyProcessing; DummyProcessing* secondProc = new DummyProcessing; net.AddProcessing( "first", firstProc ); net.AddProcessing( "second", secondProc ); CLAM::OutPortBase * outPortOfFirstProc = new CLAM::OutPort( std::string("outPortOfFirstProc"), firstProc ); CLAM::InPortBase * inPortOfSecondProc = new CLAM::InPort( std::string("inPortOfSecondProc"), secondProc ); CPPUNIT_ASSERT_EQUAL( false, net.ConnectPorts( "first.outPortOfFirstProc","second.inPortOfSecondProc") ); } void testRemovePortsConnection_WhenPortsAreNotConnected() { CLAM::Network net; DummyProcessing* firstProc = new DummyProcessing; DummyProcessing* secondProc = new DummyProcessing; net.AddProcessing( "first", firstProc ); net.AddProcessing( "second", secondProc ); CLAM::OutPortBase * outPortOfFirstProc = new CLAM::OutPort( std::string("outPortOfFirstProc"), firstProc ); CLAM::InPortBase * inPortOfSecondProc = new CLAM::InPort( std::string("inPortOfSecondProc"), secondProc ); CPPUNIT_ASSERT_EQUAL( false, net.DisconnectPorts( "first.outPortOfFirstProc","second.inPortOfSecondProc") ); } void testRemovePortsConnection_WhenPortsAreConnected() { CLAM::Network net; DummyProcessing* firstProc = new DummyProcessing; DummyProcessing* secondProc = new DummyProcessing; net.AddProcessing( "first", firstProc ); net.AddProcessing( "second", secondProc ); CLAM::OutPortBase * outPortOfFirstProc = new CLAM::OutPort( std::string("outPortOfFirstProc"), firstProc ); CLAM::InPortBase * inPortOfSecondProc = new CLAM::InPort( std::string("inPortOfSecondProc"), secondProc ); net.ConnectPorts("first.outPortOfFirstProc","second.inPortOfSecondProc"); net.DisconnectPorts( "first.outPortOfFirstProc","second.inPortOfSecondProc"); CPPUNIT_ASSERT_EQUAL( false, outPortOfFirstProc->IsVisuallyConnectedTo(*inPortOfSecondProc) ); } void testRemoveProcessing_WhenHasIt() { CLAM::Network net; DummyProcessing* proc = new DummyProcessing; net.AddProcessing( "the processing", proc ); net.RemoveProcessing( "the processing" ); CPPUNIT_ASSERT_EQUAL( false, net.HasProcessing( "the processing" )); } void testRemoveProcessing_WhenHasntIt() { CLAM::Network net; DummyProcessing* proc = new DummyProcessing; net.AddProcessing( "the processing", proc ); try{ net.RemoveProcessing( "false processing" ); CPPUNIT_FAIL("Assert expected, but no exception was thrown"); } catch( CLAM::ErrAssertionFailed& ) {} } void testConnectControls_WhenConnectionIsValid() { CLAM::Network net; DummyProcessing* firstProc = new DummyProcessing; DummyProcessing* secondProc = new DummyProcessing; net.AddProcessing( "first", firstProc ); net.AddProcessing( "second", secondProc ); const int dummyLength = 1; CLAM::OutControlBase* outControlOfFirstProc = new CLAM::FloatOutControl( std::string("outControlOfFirstProc"), firstProc ); CLAM::InControlBase* inControlOfSecondProc = new CLAM::FloatInControl( std::string("inControlOfSecondProc"), secondProc ); net.ConnectControls("first.outControlOfFirstProc","second.inControlOfSecondProc"); CPPUNIT_ASSERT_EQUAL( true, outControlOfFirstProc->IsConnectedTo(*inControlOfSecondProc) ); } void testConnectControls_WhenConnectionIsNotValid() { CLAM::Network net; DummyProcessing* firstProc = new DummyProcessing; DummyProcessing* secondProc = new DummyProcessing; net.AddProcessing( "first", firstProc ); net.AddProcessing( "second", secondProc ); const int dummyLength = 1; CLAM::OutControlBase* outControlOfFirstProc = new CLAM::FloatOutControl( std::string("outControlOfFirstProc"), firstProc ); CLAM::InControlBase* inControlOfSecondProc = new CLAM::FloatInControl( std::string("inControlOfSecondProc"), secondProc ); CPPUNIT_ASSERT_EQUAL( false, outControlOfFirstProc->IsConnectedTo(*inControlOfSecondProc) ); } void testRemoveControlsConnection_WhenControlsAreNotConnected() { CLAM::Network net; DummyProcessing* firstProc = new DummyProcessing; DummyProcessing* secondProc = new DummyProcessing; net.AddProcessing( "first", firstProc ); net.AddProcessing( "second", secondProc ); const int dummyLength = 1; CLAM::OutControlBase* outControlOfFirstProc = new CLAM::FloatOutControl( std::string("outControlOfFirstProc"), firstProc ); CLAM::InControlBase* inControlOfSecondProc = new CLAM::FloatInControl( std::string("inControlOfSecondProc"), secondProc ); CPPUNIT_ASSERT_EQUAL( false, net.DisconnectControls( "first.outControlOfFirstProc","second.inControlOfSecondProc" )); } void testRemoveControlsConnection_WhenControlsAreConnected() { CLAM::Network net; DummyProcessing* firstProc = new DummyProcessing; DummyProcessing* secondProc = new DummyProcessing; net.AddProcessing( "first", firstProc ); net.AddProcessing( "second", secondProc ); const int dummyLength = 1; CLAM::OutControlBase* outControlOfFirstProc = new CLAM::FloatOutControl( std::string("outControlOfFirstProc"), firstProc ); CLAM::InControlBase* inControlOfSecondProc = new CLAM::FloatInControl( std::string("inControlOfSecondProc"), secondProc ); net.ConnectControls("first.outControlOfFirstProc","second.inControlOfSecondProc"); CPPUNIT_ASSERT_EQUAL( true, net.DisconnectControls( "first.outControlOfFirstProc","second.inControlOfSecondProc" )); } void testStartNetworkStartsProcessings_WhenAreReady() { CLAM::Network net; CLAM::SimpleOscillator * oscillator = new CLAM::SimpleOscillator; CLAM::AudioMultiplier * multiplier = new CLAM::AudioMultiplier; net.AddProcessing( "oscillator", oscillator) ; net.AddProcessing( "multiplier", multiplier ); net.Start(); CPPUNIT_ASSERT( oscillator->IsRunning() ); CPPUNIT_ASSERT( multiplier->IsRunning() ); } void testStartNetworkDoesntStartProcessings_WhenAreNotReady() { CLAM::Network net; CLAM::SimpleOscillator * oscillator = new CLAM::SimpleOscillator; CLAM::MonoAudioFileReader * filein = new CLAM::MonoAudioFileReader; net.AddProcessing( "oscillator", oscillator) ; net.AddProcessing( "filein", filein ); net.Start(); CPPUNIT_ASSERT( oscillator->IsRunning() ); CPPUNIT_ASSERT( !filein->IsConfigured() ); } void testStopNetworkStopsProcessings_WhenAreRunning() { CLAM::Network net; CLAM::SimpleOscillator * oscillator = new CLAM::SimpleOscillator; CLAM::AudioMultiplier * multiplier = new CLAM::AudioMultiplier; net.AddProcessing( "oscillator", oscillator) ; net.AddProcessing( "multiplier", multiplier ); net.Start(); net.Stop(); CPPUNIT_ASSERT( !oscillator->IsRunning() ); CPPUNIT_ASSERT( oscillator->IsConfigured() ); CPPUNIT_ASSERT( !multiplier->IsRunning() ); CPPUNIT_ASSERT( multiplier->IsConfigured() ); } void testStopNetworkDoesntStopProcessings_WhenAreNotRunning() { CLAM::Network net; CLAM::SimpleOscillator * oscillator = new CLAM::SimpleOscillator; CLAM::MonoAudioFileReader * filein = new CLAM::MonoAudioFileReader; net.AddProcessing( "oscillator", oscillator) ; net.AddProcessing( "filein", filein ); net.Start(); net.Stop(); CPPUNIT_ASSERT( !oscillator->IsRunning() ); CPPUNIT_ASSERT( oscillator->IsConfigured() ); CPPUNIT_ASSERT( !filein->IsConfigured() ); } void testIsEmpty_whenEmpty() { CLAM::Network net; CPPUNIT_ASSERT_EQUAL( true, net.IsEmpty() ); } void testIsEmpty_whenNotEmpty() { CLAM::Network net; net.AddProcessing( "Oscillator", new CLAM::Oscillator ) ; CPPUNIT_ASSERT_EQUAL( false, net.IsEmpty() ); } void testHasMisconfiguredProcessings_whenAllConfigured() { CLAM::Network net; net.AddProcessing( "Oscillator", new CLAM::Oscillator ) ; CPPUNIT_ASSERT_EQUAL( false, net.HasMisconfiguredProcessings() ); } void testHasMisconfiguredProcessings_whenMisconfigured() { CLAM::Network net; net.AddProcessing( "Oscillator", new CLAM::Oscillator ) ; net.AddProcessing( "FileIn", new CLAM::MonoAudioFileReader ) ; CPPUNIT_ASSERT_EQUAL( true, net.HasMisconfiguredProcessings() ); } void testHasSyncSource_whenEmpty() { CLAM::Network net; CPPUNIT_ASSERT_EQUAL( false, net.HasSyncSource() ); } void testHasSyncSource_withExternalizer() { CLAM::Network net; net.AddProcessing( "AudioSink", new CLAM::AudioSink ); CPPUNIT_ASSERT_EQUAL( false, net.HasSyncSource() ); } void testSyncSourceProcessings() { CPPUNIT_ASSERT_EQUAL_MESSAGE( "AudioSink", false, CLAM::AudioSink().IsSyncSource() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "AudioSource", false, CLAM::AudioSource().IsSyncSource() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "AudioIn", true, CLAM::AudioIn().IsSyncSource() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "AudioOut", true, CLAM::AudioOut().IsSyncSource() ); } }; } // namespace clam-1.4.0/test/UnitTests/FlowControlTests/VariableBufferSizeTest.cxx0000644000000000000000000000710311344076143024444 0ustar rootroot/* * Copyright (c) 2001-2002 MUSIC TECHNOLOGY GROUP (MTG) * UNIVERSITAT POMPEU FABRA * * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include "Processing.hxx" // CLAM #include "Network.hxx" // CLAM #include "BasicFlowControl.hxx" // CLAM #include #include "BaseLoggable.hxx" #include "InPort.hxx" // CLAM #include "OutPort.hxx" // CLAM #include "InControl.hxx" // CLAM #include "OutControl.hxx" // CLAM #include "DummyProcessingData.hxx" #include "Oscillator.hxx" // CLAM #include "AudioMultiplier.hxx" // CLAM #include "MonoAudioFileReader.hxx" // CLAM #include "AudioSink.hxx" // CLAM #include "AudioSource.hxx" // CLAM #include "AudioBufferSink.hxx" // CLAM #include "AudioBufferSource.hxx" // CLAM #include "AudioOut.hxx" // CLAM #include "AudioIn.hxx" // CLAM namespace CLAMTest { class FlowChangingTest; CPPUNIT_TEST_SUITE_REGISTRATION( FlowChangingTest ); class FlowChangingTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( FlowChangingTest ); CPPUNIT_TEST( testAudioBufferSourcePropagatesAudioSize ); CPPUNIT_TEST( testAudioBufferSource_keepsAllocatedSize_changingToLowerSize ); CPPUNIT_TEST( testAudioBufferSource_keepsAllocatedSize_changingToBiggerSize ); CPPUNIT_TEST_SUITE_END(); class DummyProcessing : public CLAM::Processing { CLAM::InPort _in; unsigned _size; public: const char* GetClassName() const { return "DummyProcessing"; } bool Do() { _size=_in.GetData().GetBuffer().AllocatedSize(); _in.Consume(); return false; } unsigned getAllocatedSize() const { return _size; } DummyProcessing() : _in("Dummy In", this) , _size(0) { Configure(Config()); } }; void testAudioBufferSourcePropagatesAudioSize() { float audio[30] = {}; CLAM::AudioBufferSource source; DummyProcessing dummy; CLAM::ConnectPorts(source, 0, dummy, 0); source.Start(); dummy.Start(); source.SetExternalBuffer(audio, 30, 0); source.Do(); dummy.Do(); CPPUNIT_ASSERT_EQUAL(30u, dummy.getAllocatedSize()); } void testAudioBufferSource_keepsAllocatedSize_changingToLowerSize() { float audio[30] = {}; CLAM::AudioBufferSource source; DummyProcessing dummy; CLAM::ConnectPorts(source, 0, dummy, 0); source.Start(); dummy.Start(); source.SetExternalBuffer(audio, 30, 0); source.Do(); dummy.Do(); source.SetExternalBuffer(audio, 20, 0); source.Do(); dummy.Do(); CPPUNIT_ASSERT_EQUAL(30u, dummy.getAllocatedSize()); } void testAudioBufferSource_keepsAllocatedSize_changingToBiggerSize() { float audio[30] = {}; CLAM::AudioBufferSource source; DummyProcessing dummy; CLAM::ConnectPorts(source, 0, dummy, 0); source.Start(); dummy.Start(); source.SetExternalBuffer(audio, 20, 0); source.Do(); dummy.Do(); source.SetExternalBuffer(audio, 30, 0); source.Do(); dummy.Do(); CPPUNIT_ASSERT_EQUAL(30u, dummy.getAllocatedSize()); } }; } // namespace clam-1.4.0/test/UnitTests/FlowControlTests/TestsPhantomBufferStream.cxx0000644000000000000000000002671511326050706025040 0ustar rootroot #include #include "PhantomBuffer.hxx" // CLAM #include "WritingRegion.hxx" // CLAM #include #include // TODO to remove. Just for debugging purposes #include void Printbuffer(char* p, int size) { std::cout << "\n\n\t0 1 2 3 4\n" "\t01234567890123456789012345678901234567890123456789\n\t"; char notshowable = '·'; for (int i=0; i writer; writer.Size(5); writer.Hop(2); int initialLogicalSize = writer.LogicalStreamSize(); writer.Produce(); CPPUNIT_ASSERT_EQUAL(initialLogicalSize, writer.LogicalStreamSize() ); } //tests of logicalSize changed when link with a bigger reading region void testStreamIncreasesSizeAfterLinkingWithBiggerRegion() { CLAM::WritingRegion writer; CLAM::WritingRegion::ProperReadingRegion reader; writer.Size(5); writer.Hop(2); int sizeWithALonelyWritingRegion = writer.LogicalStreamSize(); reader.Size(9); reader.Hop(2); writer.LinkRegions(reader); CPPUNIT_ASSERT( sizeWithALonelyWritingRegion < writer.LogicalStreamSize() ); } // test phantom buffer increases after linking with bigger reading region void testPhantomBufferIncreasesAfterLinkingWithBiggerRegion() { CLAM::WritingRegion writer; CLAM::WritingRegion::ProperReadingRegion reader; writer.Size(5); writer.Hop(2); reader.Size(9); reader.Hop(2); int oldPhantomSize = writer.Stream().PhantomSize(); writer.LinkRegions(reader); CPPUNIT_ASSERT( oldPhantomSize < writer.Stream().PhantomSize() ); } // test resize reading region which is not in the begining // here we want to test the insertion point. void testInsertionPositionInLogicalZone_afterLinkingWithBiggerRegion() { CLAM::WritingRegion writer; CLAM::WritingRegion::ProperReadingRegion reader; writer.Size(5); writer.Hop(2); writer[0] = 'g'; writer[1] = 'o'; writer[2] = 'o'; writer[3] = 'd'; writer[4] = '\0'; writer.Produce(); reader.Size(9); reader.Hop(2); writer.LinkRegions(reader); CPPUNIT_ASSERT_EQUAL( std::string("od"), std::string( &(writer.Stream().operator[](18))) ); //we are inserting 16 elems + offset of 2 } void testLogicalSizeIncreases_whenWriterIncreasesItsSize() { CLAM::WritingRegion writer; CLAM::WritingRegion::ProperReadingRegion reader; writer.Size(5); writer.Hop(2); int initialSize = writer.LogicalStreamSize(); writer.Size(10); CPPUNIT_ASSERT(initialSize < writer.LogicalStreamSize() ); } void testLogicalSizeRemainsTheSame_whenWriterDecreasesItsSize() { CLAM::WritingRegion writer; CLAM::WritingRegion::ProperReadingRegion reader; writer.Size(5); writer.Hop(2); int initialSize = writer.LogicalStreamSize(); writer.Size(3); CPPUNIT_ASSERT(initialSize == writer.LogicalStreamSize() ); } //tests of logicalSize changed when reader changes its size void testLogicalSizeIncreases_whenReaderIncreasesItsSize() { CLAM::WritingRegion writer; CLAM::WritingRegion::ProperReadingRegion reader; writer.Size(5); writer.Hop(2); reader.Size(2); reader.Hop(2); int initialSize = writer.LogicalStreamSize(); writer.LinkRegions(reader); CPPUNIT_ASSERT( initialSize == writer.LogicalStreamSize() ); reader.Size( 9 ); CPPUNIT_ASSERT( initialSize < writer.LogicalStreamSize() ); } //tests of !canProduce (circular overlap) void testWriterRegionCantProduce_whenOverlapsReadingRegion() { CLAM::WritingRegion writer; CLAM::WritingRegion::ProperReadingRegion reader; writer.Size(4); writer.Hop(1); // so we can position it at the conflictive point reader.Size(1); writer.LinkRegions(reader); while( writer.Pos() <= writer.LogicalStreamSize() - writer.Size() ) { writer[0] = 'X'; writer.Produce(); } CPPUNIT_ASSERT( writer.CanProduce() == false ); } void testWriting_rearmostPos_when2ReadingRegions() { CLAM::WritingRegion writer; CLAM::WritingRegion::ProperReadingRegion firstReader; CLAM::WritingRegion::ProperReadingRegion lastReader; writer.Size(6); writer.Hop(6); firstReader.Size(4); firstReader.Hop(4); lastReader.Size(6); lastReader.Hop(3); writer.LinkRegions(firstReader); writer.LinkRegions(lastReader); writer.Produce(); firstReader.Consume(); lastReader.Consume(); CPPUNIT_ASSERT_EQUAL( 3, writer.RearmostReadingPos() ); } void testWriter_sizeReservesSizePowOf2() { int powOfNine = 512; // 512 == 2^9 (2^8 == 256) CLAM::WritingRegion writer; writer.Size( 258 / 2 ); // logical size will be the power of 2 greater and closer to size*2 CPPUNIT_ASSERT_EQUAL( powOfNine, writer.Stream().LogicalSize() ); } void testPhantomZoneGetsUpdated_whenWroteInBeginningZone() { CLAM::WritingRegion writer; writer.Size(5); // logical size == 16 (tbe pow of 2 > 5*2) writer.Hop(5); // food |phan| // 0 1 2 3 4 // 0·······90·······90·······90········90 //1 ^---^ //2 ^---^ writer[0] = 'd'; writer[1] = 'o'; writer[2] = 'g'; writer[3] = '\0'; // it IS necessary to do a writer.Produce() for updating phantom zone writer.Produce(); char *bufferbase = &(writer.Stream().operator[](0) ); //printbuffer(bufferbase, 22); CPPUNIT_ASSERT_EQUAL( std::string("dog"), std::string(bufferbase+16) ); } // idem but accessing by the pointer // TODO void testBeginningZoneGetsUpdated_whenWroteInPhantomZone() { CLAM::WritingRegion writer; writer.Size(6); // logical size == 16 (tbe pow of 2 > 6*2) writer.Hop(6); // goodbye // 0 1 2 3 4 // 0·······90·······90·······90········90 //1 ^----^ [phn] //2 ^----^ //3 ^----^ char* bufferbase = &(writer.Stream().operator[](0)); writer.Produce(); // now writer.pos == 6 writer.Produce(); // now writer.pos == 12 char* toWrite = &writer[0]; toWrite[0] = 'g'; // buffer[12] toWrite[1] = 'o'; // buffer[13] toWrite[2] = 'o'; // buffer[14] toWrite[3] = 'd'; // buffer[15] toWrite[4] = 'b'; // buffer[16] -- first position of phantom buffer toWrite[5] = 'y'; writer.Produce(); CLAM::WritingRegion::ProperReadingRegion reader; CPPUNIT_ASSERT_EQUAL('b', bufferbase[0] ); CPPUNIT_ASSERT_EQUAL('y', bufferbase[1] ); } void testPhantomZoneGetsUpdated_whenInsertedInLogicalZone() { CLAM::WritingRegion writer; writer.Size(5); // logical size == 16 (tbe pow of 2 > 5*2) writer.Hop(5); // goodbye // 0 1 2 3 4 // 0·······90·······90·······90········90 //1 ^---^ [phantm] //2 ^---^ //3 ^-------^ writer[0] = 'g'; writer[1] = 'o'; writer[2] = 'o'; writer[3] = 'd'; writer[4] = 'b'; writer.Produce(); writer[0] = 'y'; // writer.pos == 5 writer[1] = 'e'; // writer.pos == 6 writer[2] = ' '; // writer.pos == 7 writer[3] = 'h'; writer[4] = 'i'; //printbuffer( &(writer.Stream().operator[](0)), 32 ); // the following resize inserts at writer.pos == 5 writer.Size(9); // logical size == 32 (the pow of 2 > 9*2) //printbuffer( &(writer.Stream().operator[](0)), 32+5 ); char* bufferbase = &(writer.Stream().operator[](0)); CPPUNIT_ASSERT_EQUAL('y', bufferbase[21] ); CPPUNIT_ASSERT_EQUAL('e', bufferbase[22] ); CPPUNIT_ASSERT_EQUAL('g', bufferbase[32] ); CPPUNIT_ASSERT_EQUAL('o', bufferbase[33] ); CPPUNIT_ASSERT_EQUAL('o', bufferbase[34] ); CPPUNIT_ASSERT_EQUAL('d', bufferbase[35] ); //CPPUNIT_ASSERT_EQUAL('b', bufferbase[36] ); // TODO: when we want enlarge the logical-size (using size() ) // the phantom-buffer do not update using the new space. } void testIntegrityAfterBufferResize() { CLAM::WritingRegion writer; writer.Size(2); // buff size == 4 writer.Hop(2); writer[0]='A'; writer[1]='B'; writer.Produce(); writer[0]='C'; writer[1]='D'; writer.Produce(); writer.Size(4); // buff size == 8 writer.Hop(4); writer[0]='X'; writer[1]='X'; writer[2]='X'; writer[3]='X'; writer.Produce(); CPPUNIT_ASSERT_EQUAL('A', writer[0]); } void testWriterResizes_whenRearmostReaderHasSameBeginDistance() { CLAM::WritingRegion writer; writer.Size(3); // buff size = 8 writer.Hop(3); CLAM::WritingRegion::ProperReadingRegion reader; writer.LinkRegions(reader); reader.Size(1); reader.Hop(1); writer.Produce(); // pos = 3, beginDistance = 3 writer.Produce(); // pos = 6, beginDistance = 6 reader.Consume(); // pos = 1, beginDistance = 1 writer.Produce(); // pos = 9, beginDistance = 1 int oldBeginDistance = reader.BeginDistance(); writer.Size(5); // buff size = 16 CPPUNIT_ASSERT( oldBeginDistance != reader.BeginDistance() ); } void testReadingRegion_canReadInPhantomZone() { CLAM::WritingRegion writer; writer.Size(3); writer.Hop(3); CLAM::WritingRegion::ProperReadingRegion reader; writer.LinkRegions(reader); reader.Size(3); reader.Hop(3); writer.Produce(); reader.Consume(); writer.Produce(); reader.Consume(); writer[0] = 'g'; writer[1] = 'h'; writer[2] = 'i'; writer.Produce(); CPPUNIT_ASSERT_EQUAL( 'g', reader[0] ); CPPUNIT_ASSERT_EQUAL( 'h', reader[1] ); CPPUNIT_ASSERT_EQUAL( 'i', reader[2] ); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/FlowControlTests/TestsRandomStream.cxx0000644000000000000000000001227410610720021023500 0ustar rootroot#include "WritingRegion.hxx" // CLAM #include "ReadingRegion.hxx" // CLAM #include "PhantomBuffer.hxx" // CLAM #include "Assert.hxx" // CLAM #include #include #include #include #include #include #include "cppUnitHelper.hxx" namespace CLAMTest { class TestsRandomStream ; CPPUNIT_TEST_SUITE_REGISTRATION( TestsRandomStream ); class TestsRandomStream : public CppUnit::TestFixture { typedef CLAM::WritingRegion WRegion; typedef CLAM::WritingRegion::ProperReadingRegion RRegion; WRegion mWriter; RRegion mOutputReader; std::list< RRegion * > mOtherReaders; std::ifstream mInputFile; std::string mInputString; std::ostringstream mOutput; std::ostringstream mBuff; public: TestsRandomStream() : mInputFile( GetTestDataDirectory("networkTestsData/testFile.txt").c_str()), mInputString( (std::istreambuf_iterator(mInputFile)), std::istreambuf_iterator() ) { mInputFile.seekg( std::ios::beg ); std::srand(std::time(0)); } ~TestsRandomStream() { std::list< RRegion* >::iterator it; for(it=mOtherReaders.begin(); it!=mOtherReaders.end(); it++) delete *it; } CPPUNIT_TEST_SUITE( TestsRandomStream ); CPPUNIT_TEST( test ); CPPUNIT_TEST_SUITE_END(); private: bool FillWriterFromInputFile() { int inchar; for (int i=0; i=from && result <=to, "TestsRandomStream::randomIntFromTo() - " " result must be inside interval marked by parameters" ); return result; } void MaybeChangeSizeWriter() { if (ChanceOf(1-0.3)) return; int newSize = RandomIntFromTo(1, 40); mWriter.Size(newSize); mWriter.Hop(newSize); } void MaybeChangeHopWriter() { if (ChanceOf(1-0.3)) return; int newSize = RandomIntFromTo(1, mWriter.Size()); mWriter.Hop(newSize); } void MaybeChangeHopAndSizeOutputReader() { if (ChanceOf(1-0.3)) return; int newSize = RandomIntFromTo(1, 40); mOutputReader.Size(newSize); mOutputReader.Hop(newSize); } void CreateOtherReader() { int newSize = RandomIntFromTo(1, 40); RRegion * newRegion = new RRegion; newRegion->Size(newSize); newRegion->Hop(newSize); mWriter.LinkRegions( *newRegion ); mOtherReaders.push_back( newRegion ); } void CreateOtherReadersRandomly() { int nreaders = RandomIntFromTo(3, 25); for( int i=0; i::iterator it; for(it=mOtherReaders.begin(); it!=mOtherReaders.end(); it++) { if(ChanceOf(0.1)) { RRegion * toDelete = *it; mWriter.RemoveRegion( *toDelete ); mOtherReaders.remove( toDelete ); delete toDelete; return; } } } void MaybeModifyHopAndSizeOfOtherReaders() { std::list< RRegion * >::iterator it; for(it=mOtherReaders.begin(); it!=mOtherReaders.end(); it++) { if(ChanceOf(0.2)) { RRegion * otherRegion = *it; int newSize = RandomIntFromTo(1, 40); otherRegion->Size( newSize ); otherRegion->Hop( newSize ); } if(ChanceOf(0.2)) { RRegion * otherRegion = *it; int newHop = RandomIntFromTo(1, otherRegion->Size() ); otherRegion->Hop( newHop ); } } } void MaybeChangeOtherReaders() { MaybeCreateOtherReader(); MaybeRemoveOtherReader(); MaybeModifyHopAndSizeOfOtherReaders(); } void OtherReadersConsume() { std::list< RRegion * >::iterator it; for(it=mOtherReaders.begin(); it!=mOtherReaders.end(); it++) if( (*it)->CanConsume() ) { for(int i=0;i<(*it)->Size();i++) { (*it)->operator[](i); } (*it)->Consume(); } } void test() { mWriter.Size(2); mWriter.Hop(2); mWriter.LinkRegions(mOutputReader); bool endOfFile = false; CreateOtherReadersRandomly(); while(true) { if ( mWriter.CanProduce() && !endOfFile ) { endOfFile = !FillWriterFromInputFile(); CLAM_ASSERT(mWriter.CanProduce(), "mWriter should be able to produce"); mWriter.Produce(); } MaybeChangeSizeWriter(); MaybeChangeHopWriter(); // MaybeChangeHopAndSizeOutputReader(); MaybeChangeOtherReaders(); OtherReadersConsume(); if( mOutputReader.CanConsume() ) { DumpOutputReader(); mOutputReader.Consume(); } else if( endOfFile ) break; } CPPUNIT_ASSERT_EQUAL( mInputString, mOutput.str() ); } }; } // namespace CLAMTest clam-1.4.0/test/UnitTests/FlowControlTests/TestsStream.cxx0000644000000000000000000003376010442000724022346 0ustar rootroot#include "WritingRegion.hxx" // CLAM #include "ReadingRegion.hxx" // CLAM #include #include #include #include "PhantomBuffer.hxx" // CLAM #include "DataTypes.hxx" // CLAM namespace CLAMTest { // Test suite registration at the end of file // That's due to the fact that we register template specialization of the suite tmpl class // template