Initial checkin of Boost.Algorithm searching and clamp code and tests; docs and more Algos coming

[SVN r76388]
This commit is contained in:
Marshall Clow
2012-01-09 17:21:04 +00:00
parent ba417e875a
commit d518994247
27 changed files with 45652 additions and 0 deletions

22
example/Jamfile.v2 Normal file
View File

@ -0,0 +1,22 @@
# Boost algorithm library example programs Jamfile
#
# Copyright Marshall Clow 2010-2012. Use, modification and
# distribution is subject to the Boost Software License, Version
# 1.0. (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
#
# See http://www.boost.org for updates, documentation, and revision history.
project /boost/algorithm/example
: requirements
<include>../../../
<optimization>speed
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
<toolset>msvc:<define>NOMINMAX
<link>static
:
;
exe clamp_example : clamp_example.cpp ;
exe search_example : search_example.cpp ;

54
example/clamp_example.cpp Normal file
View File

@ -0,0 +1,54 @@
/*
Copyright (c) Marshall Clow 2010-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#include <string>
#include <iostream> // for cout, etc
#include <boost/algorithm/clamp.hpp>
namespace ba = boost::algorithm;
bool compare_string_lengths ( const std::string &one, const std::string &two )
{
return one.length () < two.length ();
}
int main ( int /*argc*/, char * /*argv*/ [] ) {
// Clamp takes a value and two "fenceposts", and brings the value "between" the fenceposts.
// If the input value is "between" the fenceposts, then it is returned unchanged.
std::cout << "Clamping 5 to between [1, 10] -> " << ba::clamp ( 5, 1, 10 ) << std::endl;
// If the input value is out side the range of the fenceposts, it "brought into" range.
std::cout << "Clamping 15 to between [1, 10] -> " << ba::clamp ( 15, 1, 10 ) << std::endl;
std::cout << "Clamping -15 to between [1, 10] -> " << ba::clamp ( -15, 1, 10 ) << std::endl;
// It doesn't just work for ints
std::cout << "Clamping 5.1 to between [1, 10] -> " << ba::clamp ( 5.1, 1.0, 10.0 ) << std::endl;
{
std::string one ( "Lower Bound" ), two ( "upper bound!" ), test1 ( "test#" ), test2 ( "#test" );
std::cout << "Clamping '" << test1 << "' between ['" << one << "' and '" << two << "'] -> '" <<
ba::clamp ( test1, one, two ) << "'" << std::endl;
std::cout << "Clamping '" << test2 << "' between ['" << one << "' and '" << two << "'] -> '" <<
ba::clamp ( test2, one, two ) << "'" << std::endl;
// There is also a predicate based version, if you want to compare objects in your own way
std::cout << "Clamping '" << test1 << "' between ['" << one << "' and '" << two << "'] (comparing lengths) -> '" <<
ba::clamp ( test1, one, two, compare_string_lengths ) << "'" << std::endl;
std::cout << "Clamping '" << test2 << "' between ['" << one << "' and '" << two << "'] (comparing lengths) -> '" <<
ba::clamp ( test2, one, two, compare_string_lengths ) << "'" << std::endl;
}
// Sometimes, though, you don't get quite what you expect
// This is because the two double arguments get converted to int
std::cout << "Somewhat unexpected: clamp ( 12, 14.7, 15.9 ) --> " << ba::clamp ( 12, 14.7, 15.9 ) << std::endl;
std::cout << "Expected: clamp ((double)12, 14.7, 15.9 ) --> " << ba::clamp ((double) 12, 14.7, 15.9 ) << std::endl;
return 0;
}

View File

@ -0,0 +1,57 @@
/*
Copyright (c) Marshall Clow 2010-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#include <string>
#include <iostream> // for cout, etc.
#include <boost/algorithm/searching/boyer_moore.hpp>
#include <boost/algorithm/searching/boyer_moore_horspool.hpp>
#include <boost/algorithm/searching/knuth_morris_pratt.hpp>
namespace ba = boost::algorithm;
const std::string haystack ( "ABACAB is it everywhere!" );
const std::string needle1 ( "ACAB" );
const std::string needle2 ( "not ABA" );
int main ( int /*argc*/, char * /*argv*/ [] ) {
// In search.hpp, there are generic implementations of three classic sequence search
// algorithms. They all have the same (dual) interface.
// There is a procedural interface, based on std::search:
if ( ba::boyer_moore_search ( haystack.begin (), haystack.end (), needle1.begin (), needle1.end ()) != haystack.end ())
std::cout << "Found '" << needle1 << "' in '" << haystack << "' (boyer-moore 1)" << std::endl;
else
std::cout << "Did NOT find '" << needle1 << "' in '" << haystack << "' (boyer-moore 1)" << std::endl;
// If you plan on searching for the same pattern in several different data sets,
// you can create a search object and use that over and over again - amortizing the setup
// costs across several searches
ba::boyer_moore<std::string::const_iterator> search1 ( needle1.begin (), needle1.end ());
if ( search1 ( haystack.begin (), haystack.end ()) != haystack.end ())
std::cout << "Found '" << needle1 << "' in '" << haystack << "' (boyer-moore 2)" << std::endl;
else
std::cout << "Did NOT find '" << needle1 << "' in '" << haystack << "' (boyer-moore 2)" << std::endl;
// There is also an implementation of boyer-moore-horspool searching
if ( ba::boyer_moore_horspool_search ( haystack.begin (), haystack.end (), needle1.begin (), needle1.end ()) != haystack.end ())
std::cout << "Found '" << needle1 << "' in '" << haystack << "' (boyer-moore-horspool)" << std::endl;
else
std::cout << "Did NOT find '" << needle1 << "' in '" << haystack << "' (boyer-moore-horspool)" << std::endl;
// And also the knuth-pratt-morris search algorithm
if ( ba::knuth_morris_pratt_search ( haystack.begin (), haystack.end (), needle1.begin (), needle1.end ()) != haystack.end ())
std::cout << "Found '" << needle1 << "' in '" << haystack << "' (knuth_morris_pratt)" << std::endl;
else
std::cout << "Did NOT find '" << needle1 << "' in '" << haystack << "' (knuth_morris_pratt)" << std::endl;
return 0;
}

175
include/boost/algorithm/clamp.hpp Executable file
View File

@ -0,0 +1,175 @@
/*
Copyright (c) Marshall Clow 2008-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Revision history:
27 June 2009 mtc First version
23 Oct 2010 mtc Added predicate version
*/
/// \file clamp.hpp
/// \brief Clamp algorithm
/// \author Marshall Clow
///
/// Suggested by olafvdspek in https://svn.boost.org/trac/boost/ticket/3215
#ifndef BOOST_ALGORITHM_CLAMP_HPP
#define BOOST_ALGORITHM_CLAMP_HPP
#include <functional> // For std::less
#include <iterator> // For std::iterator_traits
#include <cassert>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/mpl/identity.hpp> // for identity
#include <boost/utility/enable_if.hpp> // for boost::disable_if
namespace boost { namespace algorithm {
/// \fn clamp ( T const& val,
/// typename boost::mpl::identity<T>::type const& lo,
/// typename boost::mpl::identity<T>::type const& hi, Pred p )
/// \return the value "val" brought into the range [ lo, hi ]
/// using the comparison predicate p.
/// If p ( val, lo ) return lo.
/// If p ( hi, val ) return hi.
/// Otherwise, return the original value.
///
/// \param val The value to be clamped
/// \param lo The lower bound of the range to be clamped to
/// \param hi The upper bound of the range to be clamped to
/// \param p A predicate to use to compare the values.
/// p ( a, b ) returns a boolean.
///
template<typename T, typename Pred>
T const & clamp ( T const& val,
typename boost::mpl::identity<T>::type const & lo,
typename boost::mpl::identity<T>::type const & hi, Pred p )
{
// assert ( !p ( hi, lo )); // Can't assert p ( lo, hi ) b/c they might be equal
return p ( val, lo ) ? lo : p ( hi, val ) ? hi : val;
}
/// \fn clamp ( T const& val,
/// typename boost::mpl::identity<T>::type const& lo,
/// typename boost::mpl::identity<T>::type const& hi )
/// \return the value "val" brought into the range [ lo, hi ].
/// If the value is less than lo, return lo.
/// If the value is greater than "hi", return hi.
/// Otherwise, return the original value.
///
/// \param val The value to be clamped
/// \param lo The lower bound of the range to be clamped to
/// \param hi The upper bound of the range to be clamped to
///
template<typename T>
T const& clamp ( const T& val,
typename boost::mpl::identity<T>::type const & lo,
typename boost::mpl::identity<T>::type const & hi )
{
return (clamp) ( val, lo, hi, std::less<T>());
}
/// \fn clamp_range ( InputIterator first, InputIterator last, OutputIterator out,
/// std::iterator_traits<InputIterator>::value_type lo,
/// std::iterator_traits<InputIterator>::value_type hi )
/// \return clamp the sequence of values [first, last) into [ lo, hi ]
///
/// \param first The start of the range of values
/// \param last One past the end of the range of input values
/// \param out An output iterator to write the clamped values into
/// \param lo The lower bound of the range to be clamped to
/// \param hi The upper bound of the range to be clamped to
///
template<typename InputIterator, typename OutputIterator>
OutputIterator clamp_range ( InputIterator first, InputIterator last, OutputIterator out,
typename std::iterator_traits<InputIterator>::value_type lo,
typename std::iterator_traits<InputIterator>::value_type hi )
{
// this could also be written with bind and std::transform
while ( first != last )
*out++ = clamp ( *first++, lo, hi );
return out;
}
/// \fn clamp_range ( const Range &r, OutputIterator out,
/// typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type lo,
/// typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type hi )
/// \return clamp the sequence of values [first, last) into [ lo, hi ]
///
/// \param r The range of values to be clamped
/// \param out An output iterator to write the clamped values into
/// \param lo The lower bound of the range to be clamped to
/// \param hi The upper bound of the range to be clamped to
///
template<typename Range, typename OutputIterator>
typename boost::disable_if_c<boost::is_same<Range, OutputIterator>::value, OutputIterator>::type
clamp_range ( const Range &r, OutputIterator out,
typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type lo,
typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type hi )
{
return clamp_range ( boost::begin ( r ), boost::end ( r ), out, lo, hi );
}
/// \fn clamp_range ( InputIterator first, InputIterator last, OutputIterator out,
/// std::iterator_traits<InputIterator>::value_type lo,
/// std::iterator_traits<InputIterator>::value_type hi, Pred p )
/// \return clamp the sequence of values [first, last) into [ lo, hi ]
/// using the comparison predicate p.
///
/// \param first The start of the range of values
/// \param last One past the end of the range of input values
/// \param out An output iterator to write the clamped values into
/// \param lo The lower bound of the range to be clamped to
/// \param hi The upper bound of the range to be clamped to
/// \param p A predicate to use to compare the values.
/// p ( a, b ) returns a boolean.
///
template<typename InputIterator, typename OutputIterator, typename Pred>
OutputIterator clamp_range ( InputIterator first, InputIterator last, OutputIterator out,
typename std::iterator_traits<InputIterator>::value_type lo,
typename std::iterator_traits<InputIterator>::value_type hi, Pred p )
{
// this could also be written with bind and std::transform
while ( first != last )
*out++ = clamp ( *first++, lo, hi, p );
return out;
}
/// \fn clamp_range ( const Range &r, OutputIterator out,
/// typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type lo,
/// typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type hi,
/// Pred p )
/// \return clamp the sequence of values [first, last) into [ lo, hi ]
/// using the comparison predicate p.
///
/// \param r The range of values to be clamped
/// \param out An output iterator to write the clamped values into
/// \param lo The lower bound of the range to be clamped to
/// \param hi The upper bound of the range to be clamped to
/// \param p A predicate to use to compare the values.
/// p ( a, b ) returns a boolean.
//
// Disable this template if the first two parameters are the same type;
// In that case, the user will get the two iterator version.
template<typename Range, typename OutputIterator, typename Pred>
typename boost::disable_if_c<boost::is_same<Range, OutputIterator>::value, OutputIterator>::type
clamp_range ( const Range &r, OutputIterator out,
typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type lo,
typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type hi,
Pred p )
{
return clamp_range ( boost::begin ( r ), boost::end ( r ), out, lo, hi, p );
}
}}
#endif // BOOST_ALGORITHM_CLAMP_HPP

View File

@ -0,0 +1,268 @@
/*
Copyright (c) Marshall Clow 2010-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#ifndef BOOST_ALGORITHM_BOYER_MOORE_SEARCH_HPP
#define BOOST_ALGORITHM_BOYER_MOORE_SEARCH_HPP
#include <iterator> // for std::iterator_traits
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/algorithm/searching/detail/bm_traits.hpp>
#include <boost/algorithm/searching/detail/debugging.hpp>
namespace boost { namespace algorithm {
/*
A templated version of the boyer-moore searching algorithm.
References:
http://www.cs.utexas.edu/users/moore/best-ideas/string-searching/
http://www.cs.utexas.edu/~moore/publications/fstrpos.pdf
Explanations: boostinspect:noascii (test tool complains)
http://en.wikipedia.org/wiki/BoyerMoore_string_search_algorithm
http://www.movsd.com/bm.htm
http://www.cs.ucdavis.edu/~gusfield/cs224f09/bnotes.pdf
The Boyer-Moore search algorithm uses two tables, a "bad character" table
to tell how far to skip ahead when it hits a character that is not in the pattern,
and a "good character" table to tell how far to skip ahead when it hits a
mismatch on a character that _is_ in the pattern.
Requirements:
* Random access iterators
* The two iterator types (patIter and corpusIter) must
"point to" the same underlying type and be comparable.
* Additional requirements may be imposed but the skip table, such as:
** Numeric type (array-based skip table)
** Hashable type (map-based skip table)
*/
template <typename patIter, typename traits = detail::BM_traits<patIter> >
class boyer_moore {
typedef typename std::iterator_traits<patIter>::difference_type difference_type;
public:
boyer_moore ( patIter first, patIter last )
: pat_first ( first ), pat_last ( last ),
k_pattern_length ( std::distance ( pat_first, pat_last )),
skip_ ( k_pattern_length, -1 ),
suffix_ ( k_pattern_length + 1 )
{
this->build_skip_table ( first, last );
this->build_suffix_table ( first, last );
}
~boyer_moore () {}
/// \fn operator ( corpusIter corpus_first, corpusIter corpus_last )
/// \brief Searches the corpus for the pattern that was passed into the constructor
///
/// \param corpus_first The start of the data to search (Random Access Iterator)
/// \param corpus_last One past the end of the data to search
///
template <typename corpusIter>
corpusIter operator () ( corpusIter corpus_first, corpusIter corpus_last ) const {
BOOST_STATIC_ASSERT (( boost::is_same<
typename std::iterator_traits<patIter>::value_type,
typename std::iterator_traits<corpusIter>::value_type>::value ));
if ( corpus_first == corpus_last ) return corpus_last; // if nothing to search, we didn't find it!
if ( pat_first == pat_last ) return corpus_first; // empty pattern matches at start
const difference_type k_corpus_length = std::distance ( corpus_first, corpus_last );
// If the pattern is larger than the corpus, we can't find it!
if ( k_corpus_length < k_pattern_length )
return corpus_last;
// Do the search
return this->do_search ( corpus_first, corpus_last );
}
template <typename Range>
typename boost::range_iterator<Range>::type operator () ( Range &r ) const {
return (*this) (boost::begin(r), boost::end(r));
}
private:
/// \cond DOXYGEN_HIDE
patIter pat_first, pat_last;
const difference_type k_pattern_length;
typename traits::skip_table_t skip_;
std::vector <difference_type> suffix_;
/// \fn operator ( corpusIter corpus_first, corpusIter corpus_last, Pred p )
/// \brief Searches the corpus for the pattern that was passed into the constructor
///
/// \param corpus_first The start of the data to search (Random Access Iterator)
/// \param corpus_last One past the end of the data to search
/// \param p A predicate used for the search comparisons.
///
template <typename corpusIter>
corpusIter do_search ( corpusIter corpus_first, corpusIter corpus_last ) const {
/* ---- Do the matching ---- */
corpusIter curPos = corpus_first;
const corpusIter lastPos = corpus_last - k_pattern_length;
difference_type j, k, m;
while ( curPos <= lastPos ) {
/* while ( std::distance ( curPos, corpus_last ) >= k_pattern_length ) { */
// Do we match right where we are?
j = k_pattern_length;
while ( pat_first [j-1] == curPos [j-1] ) {
j--;
// We matched - we're done!
if ( j == 0 )
return curPos;
}
// Since we didn't match, figure out how far to skip forward
k = skip_ [ curPos [ j - 1 ]];
m = j - k - 1;
if ( k < j && m > suffix_ [ j ] )
curPos += m;
else
curPos += suffix_ [ j ];
}
return corpus_last; // We didn't find anything
}
void build_skip_table ( patIter first, patIter last ) {
for ( std::size_t i = 0; first != last; ++first, ++i )
skip_.insert ( *first, i );
}
template<typename Iter, typename Container>
void compute_bm_prefix ( Iter pat_first, Iter pat_last, Container &prefix ) {
const std::size_t count = std::distance ( pat_first, pat_last );
BOOST_ASSERT ( count > 0 );
BOOST_ASSERT ( prefix.size () == count );
prefix[0] = 0;
std::size_t k = 0;
for ( std::size_t i = 1; i < count; ++i ) {
BOOST_ASSERT ( k < count );
while ( k > 0 && ( pat_first[k] != pat_first[i] )) {
BOOST_ASSERT ( k < count );
k = prefix [ k - 1 ];
}
if ( pat_first[k] == pat_first[i] )
k++;
prefix [ i ] = k;
}
}
void build_suffix_table ( patIter pat_first, patIter pat_last ) {
const std::size_t count = (std::size_t) std::distance ( pat_first, pat_last );
if ( count > 0 ) { // empty pattern
std::vector<typename std::iterator_traits<patIter>::value_type> reversed(count);
(void) std::reverse_copy ( pat_first, pat_last, reversed.begin ());
std::vector<difference_type> prefix (count);
compute_bm_prefix ( pat_first, pat_last, prefix );
std::vector<difference_type> prefix_reversed (count);
compute_bm_prefix ( reversed.begin (), reversed.end (), prefix_reversed );
for ( std::size_t i = 0; i <= count; i++ )
suffix_[i] = count - prefix [count-1];
for ( std::size_t i = 0; i < count; i++ ) {
const std::size_t j = count - prefix_reversed[i];
const difference_type k = i - prefix_reversed[i] + 1;
if (suffix_[j] > k)
suffix_[j] = k;
}
}
}
/// \endcond
};
/* Two ranges as inputs gives us four possibilities; with 2,3,3,4 parameters
Use a bit of TMP to disambiguate the 3-argument templates */
/// \fn boyer_moore_search ( corpusIter corpus_first, corpusIter corpus_last,
/// patIter pat_first, patIter pat_last )
/// \brief Searches the corpus for the pattern.
///
/// \param corpus_first The start of the data to search (Random Access Iterator)
/// \param corpus_last One past the end of the data to search
/// \param pat_first The start of the pattern to search for (Random Access Iterator)
/// \param pat_last One past the end of the data to search for
///
template <typename patIter, typename corpusIter>
corpusIter boyer_moore_search (
corpusIter corpus_first, corpusIter corpus_last,
patIter pat_first, patIter pat_last )
{
boyer_moore<patIter> bm ( pat_first, pat_last );
return bm ( corpus_first, corpus_last );
}
template <typename PatternRange, typename corpusIter>
corpusIter boyer_moore_search (
corpusIter corpus_first, corpusIter corpus_last, const PatternRange &pattern )
{
typedef typename boost::range_iterator<PatternRange> pattern_iterator;
boyer_moore<pattern_iterator> bm ( boost::begin(pattern), boost::end (pattern));
return bm ( corpus_first, corpus_last );
}
template <typename patIter, typename CorpusRange>
typename boost::lazy_disable_if_c<
boost::is_same<CorpusRange, patIter>::value, typename boost::range_iterator<CorpusRange> >
::type
boyer_moore_search ( CorpusRange &corpus, patIter pat_first, patIter pat_last )
{
boyer_moore<patIter> bm ( pat_first, pat_last );
return bm (boost::begin (corpus), boost::end (corpus));
}
template <typename PatternRange, typename CorpusRange>
typename boost::range_iterator<CorpusRange>::type
boyer_moore_search ( CorpusRange &corpus, const PatternRange &pattern )
{
typedef typename boost::range_iterator<PatternRange> pattern_iterator;
boyer_moore<pattern_iterator> bm ( boost::begin(pattern), boost::end (pattern));
return bm (boost::begin (corpus), boost::end (corpus));
}
// Creator functions -- take a pattern range, return an object
template <typename Range>
boost::algorithm::boyer_moore<typename boost::range_iterator<const Range>::type>
make_boyer_moore ( const Range &r ) {
return boost::algorithm::boyer_moore
<typename boost::range_iterator<const Range>::type> (boost::begin(r), boost::end(r));
}
template <typename Range>
boost::algorithm::boyer_moore<typename boost::range_iterator<Range>::type>
make_boyer_moore ( Range &r ) {
return boost::algorithm::boyer_moore
<typename boost::range_iterator<Range>::type> (boost::begin(r), boost::end(r));
}
}}
#endif // BOOST_ALGORITHM_BOYER_MOORE_SEARCH_HPP

View File

@ -0,0 +1,141 @@
/*
Copyright (c) Marshall Clow 2010-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#ifndef BOOST_ALGORITHM_BOYER_MOORE_HORSPOOOL_SEARCH_HPP
#define BOOST_ALGORITHM_BOYER_MOORE_HORSPOOOL_SEARCH_HPP
#include <iterator> // for std::iterator_traits
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/algorithm/searching/detail/bm_traits.hpp>
#include <boost/algorithm/searching/detail/debugging.hpp>
// #define BOOST_ALGORITHM_BOYER_MOORE_HORSPOOL_DEBUG_HPP
namespace boost { namespace algorithm {
/*
A templated version of the boyer-moore-horspool searching algorithm.
Requirements:
* Random access iterators
* The two iterator types (patIter and corpusIter) must
"point to" the same underlying type.
* Additional requirements may be imposed buy the skip table, such as:
** Numeric type (array-based skip table)
** Hashable type (map-based skip table)
http://www-igm.univ-mlv.fr/%7Elecroq/string/node18.html
*/
template <typename patIter, typename traits = detail::BM_traits<patIter> >
class boyer_moore_horspool {
typedef typename std::iterator_traits<patIter>::difference_type difference_type;
public:
boyer_moore_horspool ( patIter first, patIter last )
: pat_first ( first ), pat_last ( last ),
k_pattern_length ( std::distance ( pat_first, pat_last )),
skip_ ( k_pattern_length, k_pattern_length ) {
// Build the skip table
std::size_t i = 0;
if ( first != last ) // empty pattern?
for ( patIter iter = first; iter != last-1; ++iter, ++i )
skip_.insert ( *iter, k_pattern_length - 1 - i );
#ifdef BOOST_ALGORITHM_BOYER_MOORE_HORSPOOL_DEBUG_HPP
skip_.PrintSkipTable ();
#endif
}
~boyer_moore_horspool () {}
/// \fn operator ( corpusIter corpus_first, corpusIter corpus_last, Pred p )
/// \brief Searches the corpus for the pattern that was passed into the constructor
///
/// \param corpus_first The start of the data to search (Random Access Iterator)
/// \param corpus_last One past the end of the data to search
/// \param p A predicate used for the search comparisons.
///
template <typename corpusIter>
corpusIter operator () ( corpusIter corpus_first, corpusIter corpus_last ) const {
BOOST_STATIC_ASSERT (( boost::is_same<
typename std::iterator_traits<patIter>::value_type,
typename std::iterator_traits<corpusIter>::value_type>::value ));
if ( corpus_first == corpus_last ) return corpus_last; // if nothing to search, we didn't find it!
if ( pat_first == pat_last ) return corpus_first; // empty pattern matches at start
const difference_type k_corpus_length = std::distance ( corpus_first, corpus_last );
// If the pattern is larger than the corpus, we can't find it!
if ( k_corpus_length < k_pattern_length )
return corpus_last;
// Do the search
return this->do_search ( corpus_first, corpus_last );
}
private:
/// \cond DOXYGEN_HIDE
patIter pat_first, pat_last;
const difference_type k_pattern_length;
typename traits::skip_table_t skip_;
/// \fn do_search ( corpusIter corpus_first, corpusIter corpus_last )
/// \brief Searches the corpus for the pattern that was passed into the constructor
///
/// \param corpus_first The start of the data to search (Random Access Iterator)
/// \param corpus_last One past the end of the data to search
/// \param k_corpus_length The length of the corpus to search
///
template <typename corpusIter>
corpusIter do_search ( corpusIter corpus_first, corpusIter corpus_last ) const {
corpusIter curPos = corpus_first;
const corpusIter lastPos = corpus_last - k_pattern_length;
while ( curPos <= lastPos ) {
// Do we match right where we are?
std::size_t j = k_pattern_length - 1;
while ( pat_first [j] == curPos [j] ) {
// We matched - we're done!
if ( j == 0 )
return curPos;
j--;
}
curPos += skip_ [ curPos [ k_pattern_length - 1 ]];
}
return corpus_last;
}
// \endcond
};
/// \fn boyer_moore_horspool_search ( corpusIter corpus_first, corpusIter corpus_last,
/// patIter pat_first, patIter pat_last )
/// \brief Searches the corpus for the pattern.
///
/// \param corpus_first The start of the data to search (Random Access Iterator)
/// \param corpus_last One past the end of the data to search
/// \param pat_first The start of the pattern to search for (Random Access Iterator)
/// \param pat_last One past the end of the data to search for
///
template <typename patIter, typename corpusIter>
corpusIter boyer_moore_horspool_search (
corpusIter corpus_first, corpusIter corpus_last,
patIter pat_first, patIter pat_last ) {
boyer_moore_horspool<patIter> bmh ( pat_first, pat_last );
return bmh ( corpus_first, corpus_last );
}
}}
#endif // BOOST_ALGORITHM_BOYER_MOORE_HORSPOOOL_SEARCH_HPP

View File

@ -0,0 +1,105 @@
/*
Copyright (c) Marshall Clow 2010-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#ifndef BOOST_ALGORITHM_SEARCH_DETAIL_BM_TRAITS_HPP
#define BOOST_ALGORITHM_SEARCH_DETAIL_BM_TRAITS_HPP
#include <climits> // for CHAR_BIT
#include <vector>
#include <iterator> // for std::iterator_traits
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/array.hpp>
#include <boost/tr1/tr1/unordered_map>
#include <boost/algorithm/searching/detail/debugging.hpp>
namespace boost { namespace algorithm { namespace detail {
//
// Default implementations of the skip tables for B-M and B-M-H
//
template<typename key_type, typename value_type, bool /*useArray*/> class skip_table;
// General case for data searching other than bytes; use a map
template<typename key_type, typename value_type>
class skip_table<key_type, value_type, false> {
private:
typedef std::tr1::unordered_map<key_type, value_type> skip_map;
const value_type k_default_value;
skip_map skip_;
public:
skip_table ( std::size_t patSize, value_type default_value )
: k_default_value ( default_value ), skip_ ( patSize ) {}
void insert ( key_type key, value_type val ) {
skip_ [ key ] = val; // Would skip_.insert (val) be better here?
}
value_type operator [] ( key_type key ) const {
typename skip_map::const_iterator it = skip_.find ( key );
return it == skip_.end () ? k_default_value : it->second;
}
void PrintSkipTable () const {
std::cout << "BM(H) Skip Table <unordered_map>:" << std::endl;
for ( typename skip_map::const_iterator it = skip_.begin (); it != skip_.end (); ++it )
if ( it->second != k_default_value )
std::cout << " " << it->first << ": " << it->second << std::endl;
std::cout << std::endl;
}
};
// Special case small numeric values; use an array
template<typename key_type, typename value_type>
class skip_table<key_type, value_type, true> {
private:
typedef typename boost::make_unsigned<key_type>::type unsigned_key_type;
typedef boost::array<value_type, 1U << (CHAR_BIT * sizeof(key_type))> skip_map;
skip_map skip_;
const value_type k_default_value;
public:
skip_table ( std::size_t patSize, value_type default_value ) : k_default_value ( default_value ) {
std::fill_n ( skip_.begin(), skip_.size(), default_value );
}
void insert ( key_type key, value_type val ) {
skip_ [ static_cast<unsigned_key_type> ( key ) ] = val;
}
value_type operator [] ( key_type key ) const {
return skip_ [ static_cast<unsigned_key_type> ( key ) ];
}
void PrintSkipTable () const {
std::cout << "BM(H) Skip Table <boost:array>:" << std::endl;
for ( typename skip_map::const_iterator it = skip_.begin (); it != skip_.end (); ++it )
if ( *it != k_default_value )
std::cout << " " << std::distance (skip_.begin (), it) << ": " << *it << std::endl;
std::cout << std::endl;
}
};
template<typename Iterator>
struct BM_traits {
typedef typename std::iterator_traits<Iterator>::difference_type value_type;
typedef typename std::iterator_traits<Iterator>::value_type key_type;
typedef boost::algorithm::detail::skip_table<key_type, value_type,
boost::is_integral<key_type>::value && (sizeof(key_type)==1)> skip_table_t;
};
}}} // namespaces
#endif // BOOST_ALGORITHM_SEARCH_DETAIL_BM_TRAITS_HPP

View File

@ -0,0 +1,30 @@
/*
Copyright (c) Marshall Clow 2010-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#ifndef BOOST_ALGORITHM_SEARCH_DETAIL_DEBUG_HPP
#define BOOST_ALGORITHM_SEARCH_DETAIL_DEBUG_HPP
#include <iostream>
/// \cond DOXYGEN_HIDE
namespace boost { namespace algorithm { namespace detail {
// Debugging support
template <typename Iter>
void PrintTable ( Iter first, Iter last ) {
std::cout << std::distance ( first, last ) << ": { ";
for ( Iter iter = first; iter != last; ++iter )
std::cout << *iter << " ";
std::cout << "}" << std::endl;
}
}}}
/// \endcond
#endif // BOOST_ALGORITHM_SEARCH_DETAIL_DEBUG_HPP

View File

@ -0,0 +1,200 @@
/*
Copyright (c) Marshall Clow 2010-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#ifndef BOOST_ALGORITHM_KNUTH_MORRIS_PRATT_SEARCH_HPP
#define BOOST_ALGORITHM_KNUTH_MORRIS_PRATT_SEARCH_HPP
#include <vector>
#include <iterator> // for std::iterator_traits
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/algorithm/searching/detail/debugging.hpp>
// #define BOOST_ALGORITHM_KNUTH_MORRIS_PRATT_DEBUG
namespace boost { namespace algorithm {
// #define NEW_KMP
/*
A templated version of the Knuth-Morris-Pratt searching algorithm.
Requirements:
* Random-access iterators
* The two iterator types (I1 and I2) must "point to" the same underlying type.
http://en.wikipedia.org/wiki/KnuthMorrisPratt_algorithm
http://www.inf.fh-flensburg.de/lang/algorithmen/pattern/kmpen.htm
*/
template <typename patIter>
class knuth_morris_pratt {
typedef typename std::iterator_traits<patIter>::difference_type difference_type;
public:
knuth_morris_pratt ( patIter first, patIter last )
: pat_first ( first ), pat_last ( last ),
k_pattern_length ( std::distance ( pat_first, pat_last )),
skip_ ( k_pattern_length + 1 ) {
#ifdef NEW_KMP
preKmp ( pat_first, pat_last );
#else
init_skip_table ( pat_first, pat_last );
#endif
#ifdef BOOST_ALGORITHM_KNUTH_MORRIS_PRATT_DEBUG
detail::PrintTable ( skip_.begin (), skip_.end ());
#endif
}
~knuth_morris_pratt () {}
/// \fn operator ( corpusIter corpus_first, corpusIter corpus_last, Pred p )
/// \brief Searches the corpus for the pattern that was passed into the constructor
///
/// \param corpus_first The start of the data to search (Random Access Iterator)
/// \param corpus_last One past the end of the data to search
/// \param p A predicate used for the search comparisons.
///
template <typename corpusIter>
corpusIter operator () ( corpusIter corpus_first, corpusIter corpus_last ) const {
BOOST_STATIC_ASSERT (( boost::is_same<
typename std::iterator_traits<patIter>::value_type,
typename std::iterator_traits<corpusIter>::value_type>::value ));
if ( corpus_first == corpus_last ) return corpus_last; // if nothing to search, we didn't find it!
if ( pat_first == pat_last ) return corpus_first; // empty pattern matches at start
const difference_type k_corpus_length = std::distance ( corpus_first, corpus_last );
// If the pattern is larger than the corpus, we can't find it!
if ( k_corpus_length < k_pattern_length )
return corpus_last;
return do_search ( corpus_first, corpus_last, k_corpus_length );
}
private:
/// \cond DOXYGEN_HIDE
patIter pat_first, pat_last;
const difference_type k_pattern_length;
std::vector <difference_type> skip_;
/// \fn operator ( corpusIter corpus_first, corpusIter corpus_last, Pred p )
/// \brief Searches the corpus for the pattern that was passed into the constructor
///
/// \param corpus_first The start of the data to search (Random Access Iterator)
/// \param corpus_last One past the end of the data to search
/// \param p A predicate used for the search comparisons.
///
template <typename corpusIter>
corpusIter do_search ( corpusIter corpus_first, corpusIter corpus_last,
difference_type k_corpus_length ) const {
difference_type match_start = 0; // position in the corpus that we're matching
#ifdef NEW_KMP
int patternIdx = 0;
while ( match_start < k_corpus_length ) {
while ( patternIdx > -1 && pat_first[patternIdx] != corpus_first [match_start] )
patternIdx = skip_ [patternIdx]; //<--- Shifting the pattern on mismatch
patternIdx++;
match_start++; //<--- corpus is always increased by 1
if ( patternIdx >= (int) k_pattern_length )
return corpus_first + match_start - patternIdx;
}
#else
// At this point, we know:
// k_pattern_length <= k_corpus_length
// for all elements of skip, it holds -1 .. k_pattern_length
//
// In the loop, we have the following invariants
// idx is in the range 0 .. k_pattern_length
// match_start is in the range 0 .. k_corpus_length - k_pattern_length + 1
const difference_type last_match = k_corpus_length - k_pattern_length;
difference_type idx = 0; // position in the pattern we're comparing
while ( match_start <= last_match ) {
while ( pat_first [ idx ] == corpus_first [ match_start + idx ] ) {
if ( ++idx == k_pattern_length )
return corpus_first + match_start;
}
// Figure out where to start searching again
// assert ( idx - skip_ [ idx ] > 0 ); // we're always moving forward
match_start += idx - skip_ [ idx ];
idx = skip_ [ idx ] >= 0 ? skip_ [ idx ] : 0;
// assert ( idx >= 0 && idx < k_pattern_length );
}
#endif
// We didn't find anything
return corpus_last;
}
void preKmp ( patIter first, patIter last ) {
const /*std::size_t*/ int count = std::distance ( first, last );
int i, j;
i = 0;
j = skip_[0] = -1;
while (i < count) {
while (j > -1 && first[i] != first[j])
j = skip_[j];
i++;
j++;
if (first[i] == first[j])
skip_[i] = skip_[j];
else
skip_[i] = j;
}
}
void init_skip_table ( patIter first, patIter last ) {
const difference_type count = std::distance ( first, last );
int j;
skip_ [ 0 ] = -1;
for ( int i = 1; i <= count; ++i ) {
j = skip_ [ i - 1 ];
while ( j >= 0 ) {
if ( first [ j ] == first [ i - 1 ] )
break;
j = skip_ [ j ];
}
skip_ [ i ] = j + 1;
}
}
// \endcond
};
/// \fn knuth_morris_pratt_search ( corpusIter corpus_first, corpusIter corpus_last,
/// patIter pat_first, patIter pat_last )
/// \brief Searches the corpus for the pattern.
///
/// \param corpus_first The start of the data to search (Random Access Iterator)
/// \param corpus_last One past the end of the data to search
/// \param pat_first The start of the pattern to search for (Random Access Iterator)
/// \param pat_last One past the end of the data to search for
///
template <typename patIter, typename corpusIter>
corpusIter knuth_morris_pratt_search (
corpusIter corpus_first, corpusIter corpus_last,
patIter pat_first, patIter pat_last ) {
knuth_morris_pratt<patIter> kmp ( pat_first, pat_last );
return kmp ( corpus_first, corpus_last );
}
}}
#endif // BOOST_ALGORITHM_KNUTH_MORRIS_PRATT_SEARCH_HPP

27
test/Jamfile.v2 Executable file
View File

@ -0,0 +1,27 @@
# Boost algorithm library test suite Jamfile ----------------------------
#
# Copyright Marshall Clow 2010-2012. Use, modification and
# distribution is subject to the Boost Software License, Version
# 1.0. (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
#
# See http://www.boost.org for updates, documentation, and revision history.
import testing ;
{
test-suite algorithm:
# Search tests
: [ run empty_search_test.cpp : : : : empty_search_test ]
[ run search_test1.cpp : : : : search_test1 ]
[ run search_test2.cpp : : : : search_test2 ]
[ run search_test3.cpp : : : : search_test3 ]
[ compile-fail search_fail1.cpp : : : : ]
[ compile-fail search_fail2.cpp : : : : ]
[ compile-fail search_fail3.cpp : : : : ]
# Clamp tests
[ run clamp_test.cpp : : : : clamp_test ]
;
}

218
test/clamp_test.cpp Executable file
View File

@ -0,0 +1,218 @@
// (C) Copyright Jesse Williamson 2009
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <iostream>
#include <vector>
#include <boost/config.hpp>
#include <boost/algorithm/clamp.hpp>
#include <boost/test/included/test_exec_monitor.hpp>
namespace ba = boost::algorithm;
bool intGreater ( int lhs, int rhs ) { return lhs > rhs; }
bool doubleGreater ( double lhs, double rhs ) { return lhs > rhs; }
class custom {
public:
custom ( int x ) : v(x) {}
custom ( const custom &rhs ) : v(rhs.v) {}
~custom () {}
custom & operator = ( const custom &rhs ) { v = rhs.v; return *this; }
bool operator < ( const custom &rhs ) const { return v < rhs.v; }
bool operator == ( const custom &rhs ) const { return v == rhs.v; } // need this for the test
std::ostream & print ( std::ostream &os ) const { return os << v; }
int v;
};
std::ostream & operator << ( std::ostream & os, const custom &x ) { return x.print ( os ); }
bool customLess ( const custom &lhs, const custom &rhs ) { return lhs.v < rhs.v; }
void test_ints()
{
// Inside the range, equal to the endpoints, and outside the endpoints.
BOOST_CHECK_EQUAL ( 3, ba::clamp ( 3, 1, 10 ));
BOOST_CHECK_EQUAL ( 1, ba::clamp ( 1, 1, 10 ));
BOOST_CHECK_EQUAL ( 1, ba::clamp ( 0, 1, 10 ));
BOOST_CHECK_EQUAL ( 10, ba::clamp ( 10, 1, 10 ));
BOOST_CHECK_EQUAL ( 10, ba::clamp ( 11, 1, 10 ));
BOOST_CHECK_EQUAL ( 3, ba::clamp ( 3, 10, 1, intGreater ));
BOOST_CHECK_EQUAL ( 1, ba::clamp ( 1, 10, 1, intGreater ));
BOOST_CHECK_EQUAL ( 1, ba::clamp ( 0, 10, 1, intGreater ));
BOOST_CHECK_EQUAL ( 10, ba::clamp ( 10, 10, 1, intGreater ));
BOOST_CHECK_EQUAL ( 10, ba::clamp ( 11, 10, 1, intGreater ));
// Negative numbers
BOOST_CHECK_EQUAL ( -3, ba::clamp ( -3, -10, -1 ));
BOOST_CHECK_EQUAL ( -1, ba::clamp ( -1, -10, -1 ));
BOOST_CHECK_EQUAL ( -1, ba::clamp ( 0, -10, -1 ));
BOOST_CHECK_EQUAL ( -10, ba::clamp ( -10, -10, -1 ));
BOOST_CHECK_EQUAL ( -10, ba::clamp ( -11, -10, -1 ));
// Mixed positive and negative numbers
BOOST_CHECK_EQUAL ( 5, ba::clamp ( 5, -10, 10 ));
BOOST_CHECK_EQUAL ( -10, ba::clamp ( -10, -10, 10 ));
BOOST_CHECK_EQUAL ( -10, ba::clamp ( -15, -10, 10 ));
BOOST_CHECK_EQUAL ( 10, ba::clamp ( 10, -10, 10 ));
BOOST_CHECK_EQUAL ( 10, ba::clamp ( 15, -10, 10 ));
// Unsigned
BOOST_CHECK_EQUAL ( 5U, ba::clamp ( 5U, 1U, 10U ));
BOOST_CHECK_EQUAL ( 1U, ba::clamp ( 1U, 1U, 10U ));
BOOST_CHECK_EQUAL ( 1U, ba::clamp ( 0U, 1U, 10U ));
BOOST_CHECK_EQUAL ( 10U, ba::clamp ( 10U, 1U, 10U ));
BOOST_CHECK_EQUAL ( 10U, ba::clamp ( 15U, 1U, 10U ));
// Mixed (1)
BOOST_CHECK_EQUAL ( 5U, ba::clamp ( 5U, 1, 10 ));
BOOST_CHECK_EQUAL ( 1U, ba::clamp ( 1U, 1, 10 ));
BOOST_CHECK_EQUAL ( 1U, ba::clamp ( 0U, 1, 10 ));
BOOST_CHECK_EQUAL ( 10U, ba::clamp ( 10U, 1, 10 ));
BOOST_CHECK_EQUAL ( 10U, ba::clamp ( 15U, 1, 10 ));
// Mixed (3)
BOOST_CHECK_EQUAL ( 5U, ba::clamp ( 5U, 1, 10. ));
BOOST_CHECK_EQUAL ( 1U, ba::clamp ( 1U, 1, 10. ));
BOOST_CHECK_EQUAL ( 1U, ba::clamp ( 0U, 1, 10. ));
BOOST_CHECK_EQUAL ( 10U, ba::clamp ( 10U, 1, 10. ));
BOOST_CHECK_EQUAL ( 10U, ba::clamp ( 15U, 1, 10. ));
short foo = 50;
BOOST_CHECK_EQUAL ( 56, ba::clamp ( foo, 56.9, 129 ));
BOOST_CHECK_EQUAL ( 24910, ba::clamp ( foo, 12345678, 123456999 ));
}
void test_floats()
{
// Inside the range, equal to the endpoints, and outside the endpoints.
BOOST_CHECK_EQUAL ( 3.0, ba::clamp ( 3.0, 1.0, 10.0 ));
BOOST_CHECK_EQUAL ( 1.0, ba::clamp ( 1.0, 1.0, 10.0 ));
BOOST_CHECK_EQUAL ( 1.0, ba::clamp ( 0.0, 1.0, 10.0 ));
BOOST_CHECK_EQUAL ( 10.0, ba::clamp ( 10.0, 1.0, 10.0 ));
BOOST_CHECK_EQUAL ( 10.0, ba::clamp ( 11.0, 1.0, 10.0 ));
BOOST_CHECK_EQUAL ( 3.0, ba::clamp ( 3.0, 10.0, 1.0, doubleGreater ));
BOOST_CHECK_EQUAL ( 1.0, ba::clamp ( 1.0, 10.0, 1.0, doubleGreater ));
BOOST_CHECK_EQUAL ( 1.0, ba::clamp ( 0.0, 10.0, 1.0, doubleGreater ));
BOOST_CHECK_EQUAL ( 10.0, ba::clamp ( 10.0, 10.0, 1.0, doubleGreater ));
BOOST_CHECK_EQUAL ( 10.0, ba::clamp ( 11.0, 10.0, 1.0, doubleGreater ));
// Negative numbers
BOOST_CHECK_EQUAL ( -3.f, ba::clamp ( -3.f, -10.f, -1.f ));
BOOST_CHECK_EQUAL ( -1.f, ba::clamp ( -1.f, -10.f, -1.f ));
BOOST_CHECK_EQUAL ( -1.f, ba::clamp ( 0.f, -10.f, -1.f ));
BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -10.f, -10.f, -1.f ));
BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -11.f, -10.f, -1.f ));
// Mixed positive and negative numbers
BOOST_CHECK_EQUAL ( 5.f, ba::clamp ( 5.f, -10.f, 10.f ));
BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -10.f, -10.f, 10.f ));
BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -15.f, -10.f, 10.f ));
BOOST_CHECK_EQUAL ( 10.f, ba::clamp ( 10.f, -10.f, 10.f ));
BOOST_CHECK_EQUAL ( 10.f, ba::clamp ( 15.f, -10.f, 10.f ));
// Mixed (1)
BOOST_CHECK_EQUAL ( 5.f, ba::clamp ( 5.f, -10., 10. ));
BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -10.f, -10., 10. ));
BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -15.f, -10., 10. ));
BOOST_CHECK_EQUAL ( 10.f, ba::clamp ( 10.f, -10., 10. ));
BOOST_CHECK_EQUAL ( 10.f, ba::clamp ( 15.f, -10., 10. ));
// Mixed (2)
BOOST_CHECK_EQUAL ( 5.f, ba::clamp ( 5.f, -10, 10 ));
BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -10.f, -10, 10 ));
BOOST_CHECK_EQUAL ( -10.f, ba::clamp ( -15.f, -10, 10 ));
BOOST_CHECK_EQUAL ( 10.f, ba::clamp ( 10.f, -10, 10 ));
BOOST_CHECK_EQUAL ( 10.f, ba::clamp ( 15.f, -10, 10 ));
}
void test_custom()
{
// Inside the range, equal to the endpoints, and outside the endpoints.
BOOST_CHECK_EQUAL ( custom( 3), ba::clamp ( custom( 3), custom(1), custom(10)));
BOOST_CHECK_EQUAL ( custom( 1), ba::clamp ( custom( 1), custom(1), custom(10)));
BOOST_CHECK_EQUAL ( custom( 1), ba::clamp ( custom( 0), custom(1), custom(10)));
BOOST_CHECK_EQUAL ( custom(10), ba::clamp ( custom(10), custom(1), custom(10)));
BOOST_CHECK_EQUAL ( custom(10), ba::clamp ( custom(11), custom(1), custom(10)));
BOOST_CHECK_EQUAL ( custom( 3), ba::clamp ( custom( 3), custom(1), custom(10), customLess ));
BOOST_CHECK_EQUAL ( custom( 1), ba::clamp ( custom( 1), custom(1), custom(10), customLess ));
BOOST_CHECK_EQUAL ( custom( 1), ba::clamp ( custom( 0), custom(1), custom(10), customLess ));
BOOST_CHECK_EQUAL ( custom(10), ba::clamp ( custom(10), custom(1), custom(10), customLess ));
BOOST_CHECK_EQUAL ( custom(10), ba::clamp ( custom(11), custom(1), custom(10), customLess ));
// Fail!!
// BOOST_CHECK_EQUAL ( custom(1), ba::clamp ( custom(11), custom(1), custom(10)));
}
#define elementsof(v) (sizeof (v) / sizeof (v[0]))
#define a_begin(v) (&v[0])
#define a_end(v) (v + elementsof (v))
#define a_range(v) v
#define b_e(v) a_begin(v),a_end(v)
void test_int_range ()
{
int inputs [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 19, 99, 999, -1, -3, -99, 234234 };
int outputs [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, -1, -1, -1, 10 };
std::vector<int> results;
std::vector<int> in_v;
std::copy ( a_begin(inputs), a_end(inputs), std::back_inserter ( in_v ));
ba::clamp_range ( a_begin(inputs), a_end(inputs), std::back_inserter ( results ), -1, 10 );
BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
results.clear ();
ba::clamp_range ( in_v.begin (), in_v.end (), std::back_inserter ( results ), -1, 10 );
BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
results.clear ();
ba::clamp_range ( a_begin(inputs), a_end(inputs), std::back_inserter ( results ), 10, -1, intGreater );
BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
results.clear ();
ba::clamp_range ( in_v.begin (), in_v.end (), std::back_inserter ( results ), 10, -1, intGreater );
BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
results.clear ();
ba::clamp_range ( a_range(inputs), std::back_inserter ( results ), -1, 10 );
BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
results.clear ();
ba::clamp_range ( in_v, std::back_inserter ( results ), -1, 10 );
BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
results.clear ();
ba::clamp_range ( a_range(inputs), std::back_inserter ( results ), 10, -1, intGreater );
BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
results.clear ();
ba::clamp_range ( in_v, std::back_inserter ( results ), 10, -1, intGreater );
BOOST_CHECK ( std::equal ( results.begin(), results.end (), outputs ));
results.clear ();
int junk[elementsof(inputs)];
ba::clamp_range ( inputs, junk, 10, -1, intGreater );
BOOST_CHECK ( std::equal ( b_e(junk), outputs ));
}
int test_main( int , char* [] )
{
test_ints ();
test_floats ();
test_custom ();
test_int_range ();
// test_float_range ();
// test_custom_range ();
return 0;
}

83
test/empty_search_test.cpp Executable file
View File

@ -0,0 +1,83 @@
/*
Copyright (c) Marshall Clow 2010-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#include <string>
#include <boost/algorithm/searching/boyer_moore.hpp>
#include <boost/algorithm/searching/boyer_moore_horspool.hpp>
#include <boost/algorithm/searching/knuth_morris_pratt.hpp>
#include <boost/test/included/test_exec_monitor.hpp>
int test_main( int argc, char *argv [] )
{
const std::string cs;
std::string estr;
std::string str ( "abc" );
// empty corpus, empty pattern
BOOST_CHECK (
boost::algorithm::boyer_moore_search (
cs.begin (), cs.end (), estr.begin (), estr.end ())
== cs.begin ()
);
BOOST_CHECK (
boost::algorithm::boyer_moore_horspool_search (
cs.begin (), cs.end (), estr.begin (), estr.end ())
== cs.begin ()
);
BOOST_CHECK (
boost::algorithm::knuth_morris_pratt_search (
cs.begin (), cs.end (), estr.begin (), estr.end ())
== cs.begin ()
);
// empty corpus, non-empty pattern
BOOST_CHECK (
boost::algorithm::boyer_moore_search (
estr.begin (), estr.end (), str.begin (), str.end ())
== estr.end ()
);
BOOST_CHECK (
boost::algorithm::boyer_moore_horspool_search (
estr.begin (), estr.end (), str.begin (), str.end ())
== estr.end ()
);
BOOST_CHECK (
boost::algorithm::knuth_morris_pratt_search (
estr.begin (), estr.end (), str.begin (), str.end ())
== estr.end ()
);
// non-empty corpus, empty pattern
BOOST_CHECK (
boost::algorithm::boyer_moore_search (
str.begin (), str.end (), estr.begin (), estr.end ())
== str.begin ()
);
BOOST_CHECK (
boost::algorithm::boyer_moore_horspool_search (
str.begin (), str.end (), estr.begin (), estr.end ())
== str.begin ()
);
BOOST_CHECK (
boost::algorithm::knuth_morris_pratt_search (
str.begin (), str.end (), estr.begin (), estr.end ())
== str.begin ()
);
(void) argv; (void) argc;
return 0;
}

26
test/search_fail1.cpp Normal file
View File

@ -0,0 +1,26 @@
/*
Copyright (c) Marshall Clow 2010-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#include <vector>
#include <boost/algorithm/searching/boyer_moore.hpp>
int main( int argc, char *argv [] )
{
std::vector<char> cv;
std::vector<int> iv;
// Should fail to compile because the underlying types are different
// They are (almost certainly) different sizes
(void) boost::algorithm::boyer_moore_search (
cv.begin (), cv.end (), iv.begin (), iv.end ());
(void) argv; (void) argc;
return 0;
}

27
test/search_fail2.cpp Normal file
View File

@ -0,0 +1,27 @@
/*
Copyright (c) Marshall Clow 2010-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#include <vector>
#include <boost/cstdint.hpp>
#include <boost/algorithm/searching/boyer_moore.hpp>
int main( int argc, char *argv [] )
{
std::vector<boost::uint8_t> cv;
std::vector<boost:: int8_t> iv;
// Should fail to compile because the underlying types are different
// They are the same size, but one is signed, and the other is not.
(void) boost::algorithm::boyer_moore_search (
cv.begin (), cv.end (), iv.begin (), iv.end ());
(void) argv; (void) argc;
return 0;
}

20
test/search_fail3.cpp Normal file
View File

@ -0,0 +1,20 @@
/*
Copyright (c) Marshall Clow 2010-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#include <vector>
#include <boost/algorithm/searching/boyer_moore.hpp>
int main( int argc, char *argv [] )
{
// Should fail to compile because the search objects are not default-constructible
boost::algorithm::boyer_moore<std::vector<char>::iterator> bm;
(void) argv; (void) argc;
return 0;
}

272
test/search_test1.cpp Executable file
View File

@ -0,0 +1,272 @@
/*
Copyright (c) Marshall Clow 2010-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#include <boost/algorithm/searching/boyer_moore.hpp>
#include <boost/algorithm/searching/boyer_moore_horspool.hpp>
#include <boost/algorithm/searching/knuth_morris_pratt.hpp>
#include <boost/test/included/test_exec_monitor.hpp>
#include <iostream>
#include <string>
#include <vector>
namespace ba = boost::algorithm;
template <typename Iter>
std::string make_str ( Iter first, std::size_t len ) {
std::string retVal ( len + 2, '\'' );
std::copy ( first, first+len, retVal.begin () + 1);
return retVal;
}
namespace {
// Check using iterators
template<typename Container>
void check_one_iter ( const Container &haystack, const std::string &needle, int expected ) {
typedef typename Container::const_iterator iter_type;
typedef std::string::const_iterator pattern_type;
iter_type hBeg = haystack.begin ();
iter_type hEnd = haystack.end ();
pattern_type nBeg = needle.begin ();
pattern_type nEnd = needle.end ();
iter_type it0 = std::search (hBeg, hEnd, nBeg, nEnd);
iter_type it1 = ba::boyer_moore_search (hBeg, hEnd, nBeg, nEnd);
iter_type it1r = ba::boyer_moore_search (haystack, nBeg, nEnd);
iter_type it2 = ba::boyer_moore_horspool_search (hBeg, hEnd, nBeg, nEnd);
iter_type it3 = ba::knuth_morris_pratt_search (hBeg, hEnd, nBeg, nEnd);
const int dist = it1 == hEnd ? -1 : std::distance ( hBeg, it1 );
std::cout << "(Iterators) Pattern is " << needle.length () << ", haysstack is " << haystack.length () << " chars long; " << std::endl;
try {
if ( it0 != it1 ) {
throw std::runtime_error (
std::string ( "results mismatch between std::search and boyer-moore search" ));
}
if ( it1 != it1r ) {
throw std::runtime_error (
std::string ( "results mismatch between iterator and range boyer_moore search" ));
}
if ( it1 != it2 ) {
throw std::runtime_error (
std::string ( "results mismatch between boyer-moore and boyer-moore-horspool search" ));
}
if ( it1 != it3 )
throw std::runtime_error (
std::string ( "results mismatch between boyer-moore and knuth-morris-pratt search" ));
}
catch ( ... ) {
std::cout << "Searching for: " << needle << std::endl;
std::cout << "Expected: " << expected << "\n";
std::cout << " std: " << std::distance ( hBeg, it0 ) << "\n";
std::cout << " bm: " << std::distance ( hBeg, it1 ) << "\n";
std::cout << " bm(r): " << std::distance ( hBeg, it1r ) << "\n";
std::cout << " bmh: " << std::distance ( hBeg, it2 ) << "\n";
std::cout << " kpm: " << std::distance ( hBeg, it3 )<< "\n";
std::cout << std::flush;
throw ;
}
BOOST_CHECK_EQUAL ( dist, expected );
}
// Check using pointers
// We're assuming that the container implements contiguous storage here.
template<typename Container>
void check_one_pointer ( const Container &haystack, const std::string &needle, int expected ) {
typedef const typename Container::value_type *ptr_type;
ptr_type hBeg = haystack.size () == 0 ? NULL : &*haystack.begin ();
ptr_type hEnd = hBeg + haystack.size ();
ptr_type nBeg = needle.size () == 0 ? NULL : &*needle.begin ();
ptr_type nEnd = nBeg + needle.size ();
ptr_type it0 = std::search (hBeg, hEnd, nBeg, nEnd);
ptr_type it1 = ba::boyer_moore_search (hBeg, hEnd, nBeg, nEnd);
ptr_type it2 = ba::boyer_moore_horspool_search (hBeg, hEnd, nBeg, nEnd);
ptr_type it3 = ba::knuth_morris_pratt_search (hBeg, hEnd, nBeg, nEnd);
const int dist = it1 == hEnd ? -1 : std::distance ( hBeg, it1 );
std::cout << "(Pointers) Pattern is " << needle.length () << ", haysstack is " << haystack.length () << " chars long; " << std::endl;
try {
if ( it0 != it1 ) {
throw std::runtime_error (
std::string ( "results mismatch between std::search and boyer-moore search" ));
}
if ( it1 != it2 ) {
throw std::runtime_error (
std::string ( "results mismatch between boyer-moore and boyer-moore-horspool search" ));
}
if ( it1 != it3 )
throw std::runtime_error (
std::string ( "results mismatch between boyer-moore and knuth-morris-pratt search" ));
}
catch ( ... ) {
std::cout << "Searching for: " << needle << std::endl;
std::cout << "Expected: " << expected << "\n";
std::cout << " std: " << std::distance ( hBeg, it0 ) << "\n";
std::cout << " bm: " << std::distance ( hBeg, it1 ) << "\n";
std::cout << " bmh: " << std::distance ( hBeg, it2 ) << "\n";
std::cout << " kpm: " << std::distance ( hBeg, it3 )<< "\n";
std::cout << std::flush;
throw ;
}
BOOST_CHECK_EQUAL ( dist, expected );
}
// Check using objects
template<typename Container>
void check_one_object ( const Container &haystack, const std::string &needle, int expected ) {
typedef typename Container::const_iterator iter_type;
typedef std::string::const_iterator pattern_type;
iter_type hBeg = haystack.begin ();
iter_type hEnd = haystack.end ();
pattern_type nBeg = needle.begin ();
pattern_type nEnd = needle.end ();
ba::boyer_moore<pattern_type> bm_r = ba::make_boyer_moore ( needle );
ba::boyer_moore<pattern_type> bm ( nBeg, nEnd );
ba::boyer_moore_horspool<pattern_type> bmh ( nBeg, nEnd );
ba::knuth_morris_pratt<pattern_type> kmp ( nBeg, nEnd );
iter_type it0 = std::search (hBeg, hEnd, nBeg, nEnd);
iter_type it1 = bm (hBeg, hEnd);
iter_type it1r = bm (haystack);
iter_type rt1 = bm_r (hBeg, hEnd);
iter_type rt1r = bm_r (haystack);
iter_type it2 = bmh (hBeg, hEnd);
iter_type it3 = kmp (hBeg, hEnd);
const int dist = it1 == hEnd ? -1 : std::distance ( hBeg, it1 );
std::cout << "(Objects) Pattern is " << needle.length () << ", haysstack is " << haystack.length () << " chars long; " << std::endl;
try {
if ( it0 != it1 ) {
throw std::runtime_error (
std::string ( "results mismatch between std::search and boyer-moore search" ));
}
if ( it1 != it1r ) {
throw std::runtime_error (
std::string ( "results mismatch between iterator and range boyer_moore search(1)" ));
}
if ( it1 != rt1 ) {
throw std::runtime_error (
std::string ( "results mismatch between iterator and range boyer_moore search(2)" ));
}
if ( rt1 != rt1r ) {
throw std::runtime_error (
std::string ( "results mismatch between iterator and range boyer_moore search(3)" ));
}
if ( it1 != it2 ) {
throw std::runtime_error (
std::string ( "results mismatch between boyer-moore and boyer-moore-horspool search" ));
}
if ( it1 != it3 )
throw std::runtime_error (
std::string ( "results mismatch between boyer-moore and knuth-morris-pratt search" ));
}
catch ( ... ) {
std::cout << "Searching for: " << needle << std::endl;
std::cout << "Expected: " << expected << "\n";
std::cout << " std: " << std::distance ( hBeg, it0 ) << "\n";
std::cout << " bm: " << std::distance ( hBeg, it1 ) << "\n";
std::cout << " bm(r1): " << std::distance ( hBeg, it1r ) << "\n";
std::cout << " bm(r2): " << std::distance ( hBeg, rt1 ) << "\n";
std::cout << " bm(r3): " << std::distance ( hBeg, rt1r ) << "\n";
std::cout << " bmh: " << std::distance ( hBeg, it2 ) << "\n";
std::cout << " kpm: " << std::distance ( hBeg, it3 )<< "\n";
std::cout << std::flush;
throw ;
}
BOOST_CHECK_EQUAL ( dist, expected );
}
template<typename Container>
void check_one ( const Container &haystack, const std::string &needle, int expected ) {
check_one_iter ( haystack, needle, expected );
check_one_pointer ( haystack, needle, expected );
check_one_object ( haystack, needle, expected );
}
}
int test_main( int , char* [] )
{
std::string haystack1 ( "NOW AN FOWE\220ER ANNMAN THE ANPANMANEND" );
std::string needle1 ( "ANPANMAN" );
std::string needle2 ( "MAN THE" );
std::string needle3 ( "WE\220ER" );
std::string needle4 ( "NOW " ); // At the beginning
std::string needle5 ( "NEND" ); // At the end
std::string needle6 ( "NOT FOUND" ); // Nowhere
std::string needle7 ( "NOT FO\340ND" ); // Nowhere
std::string haystack2 ( "ABC ABCDAB ABCDABCDABDE" );
std::string needle11 ( "ABCDABD" );
std::string haystack3 ( "abra abracad abracadabra" );
std::string needle12 ( "abracadabra" );
std::string needle13 ( "" );
std::string haystack4 ( "" );
check_one ( haystack1, needle1, 26 );
check_one ( haystack1, needle2, 18 );
check_one ( haystack1, needle3, 9 );
check_one ( haystack1, needle4, 0 );
check_one ( haystack1, needle5, 33 );
check_one ( haystack1, needle6, -1 );
check_one ( haystack1, needle7, -1 );
check_one ( needle1, haystack1, -1 ); // cant find long pattern in short corpus
check_one ( haystack1, haystack1, 0 ); // find something in itself
check_one ( haystack2, haystack2, 0 ); // find something in itself
check_one ( haystack2, needle11, 15 );
check_one ( haystack3, needle12, 13 );
check_one ( haystack1, needle13, 0 ); // find the empty string
check_one ( haystack4, needle1, -1 ); // can't find in an empty haystack
// Mikhail Levin <svarneticist@gmail.com> found a problem, and this was the test
// that triggered it.
const std::string mikhail_pattern =
"GATACACCTACCTTCACCAGTTACTCTATGCACTAGGTGCGCCAGGCCCATGCACAAGGGCTTGAGTGGATGGGAAGGA"
"TGTGCCCTAGTGATGGCAGCATAAGCTACGCAGAGAAGTTCCAGGGCAGAGTCACCATGACCAGGGACACATCCACGAG"
"CACAGCCTACATGGAGCTGAGCAGCCTGAGATCTGAAGACACGGCCATGTATTACTGTGGGAGAGATGTCTGGAGTGGT"
"TATTATTGCCCCGGTAATATTACTACTACTACTACTACATGGACGTCTGGGGCAAAGGGACCACG"
;
const std::string mikhail_corpus = std::string (8, 'a') + mikhail_pattern;
check_one ( mikhail_corpus, mikhail_pattern, 8 );
return 0;
}

145
test/search_test2.cpp Executable file
View File

@ -0,0 +1,145 @@
/*
Copyright (c) Marshall Clow 2010-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#include <boost/algorithm/searching/boyer_moore.hpp>
#include <boost/algorithm/searching/boyer_moore_horspool.hpp>
#include <boost/algorithm/searching/knuth_morris_pratt.hpp>
#include <boost/test/included/test_exec_monitor.hpp>
#include <iostream>
#include <algorithm>
#include <vector>
typedef std::vector<char> vec;
#define NUM_TRIES 100
#define runOne(call, refDiff) { \
std::clock_t bTime, eTime; \
bTime = std::clock (); \
for ( i = 0; i < NUM_TRIES; ++i ) { \
res = boost::algorithm::call \
( haystack.begin (), haystack.end (), \
needle.begin (), needle.end ()); \
if ( res != exp ) { \
std::cout << "On run # " << i << " expected " \
<< exp - haystack.begin () << " got " \
<< res - haystack.begin () << std::endl; \
throw std::runtime_error \
( "Unexpected result from " #call ); \
} \
} \
eTime = std::clock (); \
printRes ( #call, eTime - bTime, refDiff ); }
#define runObject(obj, refDiff) { \
std::clock_t bTime, eTime; \
bTime = std::clock (); \
boost::algorithm::obj <vec::const_iterator> \
s_o ( needle.begin (), needle.end ()); \
for ( i = 0; i < NUM_TRIES; ++i ) { \
res = s_o ( haystack.begin (), haystack.end ()); \
if ( res != exp ) { \
std::cout << "On run # " << i << " expected " \
<< exp - haystack.begin () << " got " \
<< res - haystack.begin () << std::endl; \
throw std::runtime_error \
( "Unexpected result from " #obj " object" ); \
} \
} \
eTime = std::clock (); \
printRes ( #obj " object", eTime - bTime, refDiff ); }
namespace {
vec ReadFromFile ( const char *name ) {
std::ifstream in ( name, std::ios_base::binary | std::ios_base::in );
vec retVal;
std::istream_iterator<char, char> begin(in);
std::istream_iterator<char, char> end;
std::copy ( begin, end, std::back_inserter ( retVal ));
return retVal;
}
void printRes ( const char *prompt, unsigned long diff, unsigned long stdDiff ) {
std::cout
<< std::setw(34) << prompt << " "
<< std::setw(6) << ( 1.0 * diff) / CLOCKS_PER_SEC << " seconds\t"
<< std::setw(5) << (100.0 * diff) / stdDiff << "% \t"
<< std::setw(12) << diff;
if ( diff > stdDiff )
std::cout << " !!";
std::cout << std::endl;
}
void check_one ( const vec &haystack, const vec &needle, int expected ) {
std::size_t i;
std::clock_t sTime;
unsigned long stdDiff;
vec::const_iterator res;
vec::const_iterator exp; // the expected result
if ( expected >= 0 )
exp = haystack.begin () + expected;
else if ( expected == -1 )
exp = haystack.end (); // we didn't find it!
else if ( expected == -2 )
exp = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ());
else
throw std::logic_error ( "Expected must be -2, -1, or >= 0" );
std::cout << "Pattern is " << needle.size () << " entries long" << std::endl;
std::cout << "Corpus is " << haystack.size () << " entries long" << std::endl;
// First, the std library search
sTime = std::clock ();
for ( i = 0; i < NUM_TRIES; ++i ) {
res = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ());
if ( res != exp ) {
std::cout << "On run # " << i << " expected " << exp - haystack.begin () << " got " << res - haystack.begin () << std::endl;
throw std::runtime_error ( "Unexpected result from std::search" );
}
}
stdDiff = std::clock () - sTime;
printRes ( "std::search", stdDiff, stdDiff );
runOne ( boyer_moore_search, stdDiff );
runObject ( boyer_moore, stdDiff );
runOne ( boyer_moore_horspool_search, stdDiff );
runObject ( boyer_moore_horspool, stdDiff );
runOne ( knuth_morris_pratt_search, stdDiff );
runObject ( knuth_morris_pratt, stdDiff );
}
}
int test_main( int , char* [] )
{
vec c1 = ReadFromFile ( "search_test_data/0001.corpus" );
vec p1b = ReadFromFile ( "search_test_data/0001b.pat" );
vec p1e = ReadFromFile ( "search_test_data/0001e.pat" );
vec p1n = ReadFromFile ( "search_test_data/0001n.pat" );
vec p1f = ReadFromFile ( "search_test_data/0001f.pat" );
std::cout << std::ios::fixed << std::setprecision(4);
// std::cout << "Corpus is " << c1.size () << " entries long\n";
std::cout << "--- Beginning ---" << std::endl;
check_one ( c1, p1b, 0 ); // Find it at position zero
std::cout << "---- Middle -----" << std::endl;
check_one ( c1, p1f, -2 ); // Don't know answer
std::cout << "------ End ------" << std::endl;
check_one ( c1, p1e, c1.size() - p1e.size ());
std::cout << "--- Not found ---" << std::endl;
check_one ( c1, p1n, -1 ); // Not found
return 0;
}

145
test/search_test3.cpp Executable file
View File

@ -0,0 +1,145 @@
/*
Copyright (c) Marshall Clow 2010-2012.
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
For more information, see http://www.boost.org
*/
#include <boost/algorithm/searching/boyer_moore.hpp>
#include <boost/algorithm/searching/boyer_moore_horspool.hpp>
#include <boost/algorithm/searching/knuth_morris_pratt.hpp>
#include <boost/test/included/test_exec_monitor.hpp>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
typedef std::vector<std::string> vec;
#define NUM_TRIES 100
#define runOne(call, refDiff) { \
std::clock_t bTime, eTime; \
bTime = std::clock (); \
for ( i = 0; i < NUM_TRIES; ++i ) { \
res = boost::algorithm::call \
( haystack.begin (), haystack.end (), \
needle.begin (), needle.end ()); \
if ( res != exp ) { \
std::cout << "On run # " << i << " expected " \
<< exp - haystack.begin () << " got " \
<< res - haystack.begin () << std::endl; \
throw std::runtime_error \
( "Unexpected result from " #call ); \
} \
} \
eTime = std::clock (); \
printRes ( #call, eTime - bTime, refDiff ); }
#define runObject(obj, refDiff) { \
std::clock_t bTime, eTime; \
bTime = std::clock (); \
boost::algorithm::obj <vec::const_iterator> \
s_o ( needle.begin (), needle.end ()); \
for ( i = 0; i < NUM_TRIES; ++i ) { \
res = s_o ( haystack.begin (), haystack.end ()); \
if ( res != exp ) { \
std::cout << "On run # " << i << " expected " \
<< exp - haystack.begin () << " got " \
<< res - haystack.begin () << std::endl; \
throw std::runtime_error \
( "Unexpected result from " #obj " object" ); \
} \
} \
eTime = std::clock (); \
printRes ( #obj " object", eTime - bTime, refDiff ); }
namespace {
vec ReadFromFile ( const char *name ) {
std::ifstream in ( name, std::ios_base::binary | std::ios_base::in );
std::string temp;
vec retVal;
while ( std::getline ( in, temp ))
retVal.push_back ( temp );
return retVal;
}
void printRes ( const char *prompt, unsigned long diff, unsigned long stdDiff ) {
std::cout
<< std::setw(34) << prompt << " "
<< std::setw(6) << ( 1.0 * diff) / CLOCKS_PER_SEC << " seconds\t"
<< std::setw(5) << (100.0 * diff) / stdDiff << "% \t"
<< std::setw(12) << diff;
if ( diff > stdDiff )
std::cout << " !!";
std::cout << std::endl;
}
void check_one ( const vec &haystack, const vec &needle, int expected ) {
std::size_t i;
std::clock_t sTime;
unsigned long stdDiff;
vec::const_iterator res;
vec::const_iterator exp; // the expected result
if ( expected >= 0 )
exp = haystack.begin () + expected;
else if ( expected == -1 )
exp = haystack.end (); // we didn't find it1
else if ( expected == -2 )
exp = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ());
else
throw std::logic_error ( "Expected must be -2, -1, or >= 0" );
std::cout << "Pattern is " << needle.size () << " entries long" << std::endl;
std::cout << "Corpus is " << haystack.size () << " entries long" << std::endl;
// First, the std library search
sTime = std::clock ();
for ( i = 0; i < NUM_TRIES; ++i ) {
res = std::search ( haystack.begin (), haystack.end (), needle.begin (), needle.end ());
if ( res != exp ) {
std::cout << "On run # " << i << " expected " << exp - haystack.begin () << " got " << res - haystack.begin () << std::endl;
throw std::runtime_error ( "Unexpected result from std::search" );
}
}
stdDiff = std::clock () - sTime;
printRes ( "std::search", stdDiff, stdDiff );
runOne ( boyer_moore_search, stdDiff );
runObject ( boyer_moore, stdDiff );
runOne ( boyer_moore_horspool_search, stdDiff );
runObject ( boyer_moore_horspool, stdDiff );
runOne ( knuth_morris_pratt_search, stdDiff );
runObject ( knuth_morris_pratt, stdDiff );
}
}
int test_main( int , char* [] )
{
vec c1 = ReadFromFile ( "search_test_data/0001.corpus" );
vec p1b = ReadFromFile ( "search_test_data/0002b.pat" );
vec p1e = ReadFromFile ( "search_test_data/0002e.pat" );
vec p1n = ReadFromFile ( "search_test_data/0002n.pat" );
vec p1f = ReadFromFile ( "search_test_data/0002f.pat" );
std::cout << std::ios::fixed << std::setprecision(4);
// std::cout << "Corpus is " << c1.size () << " entries long\n";
std::cout << "--- Beginning ---" << std::endl;
check_one ( c1, p1b, 0 ); // Find it at position zero
std::cout << "---- Middle -----" << std::endl;
check_one ( c1, p1f, -2 ); // Don't know answer
std::cout << "------ End ------" << std::endl;
check_one ( c1, p1e, c1.size() - p1e.size ());
std::cout << "--- Not found ---" << std::endl;
check_one ( c1, p1n, -1 ); // Not found
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
TU0AKgAfhPqScHN4dnZ2e3p5e3h7eXl4dnd1dnV3enp5dnd3dHV1dHNzd3l3eHh5
eXZ4dXd2dHNwcHFwcXBxc3h0dHN1eHVzcXV1dXV2c3h5dHV3eHVwcHF

View File

@ -0,0 +1,2 @@
iBJbmMuLCBhbGwg
cmlnaHRzIHJlc2VydmVkLgAAAAA=

View File

@ -0,0 +1,2 @@
q/y9PZ3uHj5ufo6UJDQ0NFQz8+RUZBQEBAOzo6Ozs4Nz06Ojs4Ojo9PT47Ojk0
Nzc7OjQ6NzU6OjgxMzg1OjY2NjU3NTU1Nzc3NTU1NzU

View File

@ -0,0 +1,2 @@
TIzMjIyMjM0MjM1nTQzNTc3MzY1NDU2NzQ2MjEwMjU1MTQ2NzU0NDI1
NDMyMzQxMzQ0NDU1MjU2NTc5NzU1NDc4ODY1

View File

@ -0,0 +1,170 @@
TU0AKgAfhPqScHN4dnZ2e3p5e3h7eXl4dnd1dnV3enp5dnd3dHV1dHNzd3l3eHh5
eXZ4dXd2dHNwcHFwcXBxc3h0dHN1eHVzcXV1dXV2c3h5dHV3eHVwcHF1d3V0dXJy
cXNzcHBwcHJyc3R0dXl7eHJycnF1dHV2d3h4eHV0cnRycXN1dXN0c3R0c3R0cXJx
cHNxb3B0c29scHFybm9sbGpscXJ1c3NycXN0cHFvb3JzdHBycG9vb29vb29ubXBt
bG9vcW5tbGptb3Fwb3Bwb25vbXFtbGtvbGlrbnBuamxsbW1rbW1vbm1ub3Btamxw
bWpsbG9xcG5ua2tpamhqZ2hnam5saWhsbG1nZmZnZ2lnamtxa2ppZWZmZWlrZ2hp
Z2hraWRmZ2psa2pmZWVkZmplZWZiYF1gZGVlYmJiY2RhY2NiYVxdW1xgXl9iZV9d
X11hXF5gZWJhYF5dXWFmYl9hXl5gXmBhZGFhYV1cYWFiX2FgXFxgYF5iYmNiYWRk
YWFjYGFgXl9jYmVlZGZiYV1cXFtbW1pYV1dVV1VWVlFQT1FRUVBRTkxLSktNTVFP
UU1RUVBSUlBPUlNTUVRWWFpcVldXWldXVVhYVlpbWV1dX1tbW11fYWFdXV5iY2Rg
YFxeYmNmZGJgYFxdYmdjYWFhYGJoZGReXF9gX2BhYWJhXltdXVtaXGJlYV5gYF9f
XVxcX2JiYWJkZmNjZGNhYmFcW15dXmBgX1xdYF5fXF5eX15bWV1dXl9eWlldXGJf
XmFgXVpcXF1dXlpdXl9dXWRlYF5cXFtfYF1eYl1hX1xbXV1ZV1hZWltbW1peW1lb
XlteW1xeXlxbXVpYW11dY19fW1xfX2NhXV5hZWNfX2FjZGJlZmVoaWtlY2FkXl5f
YWJjX19fX15dXWBjYmJeWlteXVlaXmBeXF1fXVxdXFtaW19dXFtfWllZWVxeXlxb
XV9eW1xcXF5cW1paVVdbWVteW1pbWlZeYV1ZV1tYVlVWV1hbWVhcWVhVWlhbWFtX
V1ZWWFtXVlZaVlRVVVdVVldWVlNRU1NTUVNXVVlZWVZVVFNWVlRTU1JVV1ZWVFRU
UVFVWVpZWlZWWFpYWllcXVpYWFdWWFxbWFlYWVhVVVRVV1dZWllYV1lcXVpcWVhY
V1VbW1tVVVdaXFpXVlZZW1leW1lWWFdaXVpXWlZXW1xdXFxgX1xYXVxcXFhaW1tb
WlxcWltdWldXVldXWVZVUVJVWFlcW1tcWVpgXF9hX11aWVpdXFxeXFtbX19aW1lb
W1paWlxdXVpaXVxeX1xdX2JjYV9gYl9cW1xbWFpeXl1gYGBgYFtdY2JhYmBgYGBe
YGJkY2NjYmNjYGNiY2JgX19hYV1gX2BgX19hZWRiZWJjZWVgYmFiZGRmaWdmYWJj
YmJjZGFhY2FhY2RkZmVmY2FhYWVnaWVjZGNhY2RlZWZqZ2doZ2RjZGRmaGVlZmZm
Z2dnaGhoZ2hmY2VmZWZjZWNlaWdlZmVoZ2hpamlra2hram1samtqZWpuc2tpa21u
bmtraWtqYWNmZmZmZGVpZ2p0kMLk8vv+/////////5drcHZ1dnd7fHt6end0c3V1
dnR0d3l3d3Z3fH16dnV2d3h0d3l2d3h4dXZ3d3d3dnBucW5vb3BxdHR3d3Jzd3Vz
dndzc3V6eHVyc3JydXZxc3Z1d3V0eHZ1c3Bvc3V0dnR0dXR0dHd4dnRxc3J0c3d3
dXNycXd1dnVzcHJ0d3h0dHFwcXFzc3N0dXFxcXFwcHFwcnFycHJwcHJzc3Fwc3Nx
cnRyc29ucHJ0cnBwb29ub3Fwc3R0cnJubnBycG1ucHBxcXBuc3FwbGpoamlsb3By
c25qaW1tcW1qbXFua25xb21vcG9tbG5qa2doaW1sbGpqamxsaWpmZ2VlZ2tqZ2Zn
amVoa2tvZ2ttamxpamlmZmdoZ2dnZ2traWZmaGlpa2loaGdmZ2ZoZmRnZ2ZmZ2Vl
ZmJiZWBhYmBhZGBhX2BfXVxfYmJkZF5dY2JjYWNhY2BgXl5gXl5dXl5cXFxgZGVh
Xl5eXlxeXl5iYl9fYF9iYWFhZWRkY2RgX2BhX19gY2VlZWRkZF1gYV9bWV1dWVxX
WldXVlZVU1BQUE5QUU9SUU5NUE9OTk9NT1FRUk5PUVRUUVJSVFVYWVpXVldVVlRV
V1dZXl9bW1pYWVhaXl9gXl5bYGJhYWFhX19jZGZmZGJgYF9eX19fYWRmX2RgYWBe
XmFhYWNhYmBeXV5eW1xdYF5dX2NiX19hX11dYmVoY2RlZWFeYF5fXV5hYGFgYF9i
Y19dXl5dYGNgXFZbXlxZWVxhYl5gYF9cXV1cXFxdX19gYVxZW11dX2NjXF5eXF5e
Xl9eYGJfXl9eW1xcX11ZW1xdW15eW11gXl1dW11cX15dXl1cXF5iX2BgYV9iYmJf
XF1mY2NiamZiYWNiY2JiYmVpbGdkYGBmY2VoY11dXFxcX15iYmFiYmBeW19hX19h
XV5aYlxZWlxcW1xcW2BfW1hZXF5cXVtcXlxbWldYW1xcXVpYWFlYWllbW1paWFpe
XFtYWFdUU1ZVWFhVWFteWFdYW1pYVlhVU1RVWVZXVVdXVVFSU1ZWVFNSVVtSUlJT
UlNUVVVWVVVWVVJWVVVTVldXXFlXVVlbVVNUWVtXWVtVVVZVWltZWltYVVVZWVlY
V1ZXWVVUV1dXWl1dW1tcX1lZWl5cXVtcWVVXXFxZXVxZVVRUWVlcWVZWWFhaWFtd
WV5YVlZZWVxbXFxdXFtbXl5dXVtbWV5dYF9cXl9eXF9iXl5bWlhbWltZWFpgXlpa
W15iXF1jYVtcYGBfXVpbXFxcWlxbXFtZXFxaWllaXl1aW11gXV5fX19fX19hXl5f
YGFgYWBhXmBiXlxfXFtcXmBgYmJkYWJgYmNgYGJiYWBfX19jZWBeYWJgYFxcY2Vj
ZGJfX2JiYWNmY2RjYmFhYWFjYWNpZmNjZ2ZkZGBiYmVmZ2VjYmNlZV9iZWhlZWJi
Y2JmZWdoZWVoZmdrZ2VmZmhmZGRkZ2VmZmVkZmppZmVnaGhqamhiZmZnaWdnamZm
ZmtubGtpZWhna21rZmRpaWVlZ2l0bGtrbG1obmdmamZnaGVkZGNobYekwePx+///
////////l2pzdnh3fHt8enp5fnl2d3Vyc3d5eXd1d3d3eXx+eHp3eHR0d3d6enl1
dHNzc3d1dXNwcHJ0c3Byc3V3eXVycnZ5enl3dnh3dnJxdHZ3dXh8eHl1dXZ3dnZ1
dHV0ent2dXl3dXV1d3h3dnZ3enV0d3d0dXN3dXZ1dnd3d3h6eHZzc3JwcnN0dHJy
cXFub3FycW9vcHBvbGxsbXFzcHF1c3N0dHR0c3Bvc3N1cnFvcW9tbXFzcm5ub3Bw
b21ucXBxcXBvc3Bvbm5sa25sbW1vbnJ0b2trbWpqbGtsbnFxcG9vbm1xbm5tbGpp
amtqbm1rbW9sa21taWhoZmlqaGlramxqaWdraGdqaWluam9ua2psamhkZmxpaWpq
aWVlZWdnaGZjY2RpZmZnZmZmZ2ZnZGFhZWNgZGJhY11dXV5hXF9lZGRiY2JhYV5f
YGZgYF5fYWJgYmBgX15gZF9eYF1gYlxeYV5fYV5eYF5gYWJkX2JhZGNlZGJjYmFh
YWNgY2VhZGZkY2JgYWBjY15fXFtaWllaXFlYVlNRUVNTUU5PUlNSVlRPU09PUVJS
U1FNT1JVUk9RU1NRU1NSVFRWVllWWFtXWFhaWlpeXl1hYV9cXV5fXl9gXmFgYGBh
ZmJjYmJjYV9fX19dYWFiZmRiYWBeX2FcW15fYWBfXmNkX11cXF1cXVxfYl9hYWJd
X2BhY2JjX2BkZGFgYWFfYWFgYF9eX2JiZGVjY19dYF9eXV1eXF9hXmBeXF1fXV9b
XGFhY2FkX11dW1peXl9hYWJgX19jYV5dYGFgYGBdWV5cXV9hYGBcX2BhYF5gZWBb
X19dXWBeXl1eYWNhXl1eYGFhYGFgYWFhZGNiZGZoZWdnZWNgXWFhX2NlY2NjYGBl
Y2NjY11bXl9eXmBiYGFgXF9kYF5iYF9iYl9cW15aWV5fXFtaWVpdW1xfYGBfXV5d
XFtcWlhXVlZWWFhYV1ZWV1daWlhbWlpcXFhaWFdYVldYWFlZWWFYWltYWVhSVFdV
VlpWV1RYV1VTVFRYVVRWU1RUVVhWVVRUVFZXVFVXV1VWV1ZYV1lcbltbWV5ZWlpX
V1VSWFtfW1laXV5bWFpZWlpYWVhYW1hYV1daWVlZV15dWlxgXVpZWV1hXFpbW1dY
WlpZVldXWlpWVlZXWlhaWVlZWVpZW1xbWltcWVhaXVxdWVxZWVtaX2BfXFlaWVte
XV5dXV9eXF9bW1xbXl9hXFdcXlxbWVpbXFpcWF1gXV9gYF9aW11cX15dX19gXFtY
WVtZW1tdXWBiYWBfXV5cXV5dX15eXV1iZWRhYWFiYF9eYmBeXV5dYWBdXWBlY2Fh
YWRfYF9hY2RhZGJjZGZjYmJfYV5fZGJkYWBgYGBjY2RlaGNhY2BjYF9eYWJgY2Vk
Y2JlZWRhYmRlY2FjY2RjY2RjY2NjYWBkY2NjZGVjYWRnaGhramtqZmdnZmhoZ2pn
aGhoZmhpa2lpaGhoZ2hlZmdqaGZsbWhpamlqamppa21qaGhmaGxqZWVra25sbW5p
aWhraWprbW1pZ2ZoZ2hsfKXG4/D7//////////+UbnR5e3t6eHmAfH58eHZ2dHd2
d3x3dHZ2dnl4eHt8fHh4dXVydXR3eXd2dXR4d3Z1dXZ1dnhydHd5d3ZzdHV4dXR2
eX13dnV2dHN1eXh4eHd3dnd2d3Z3dXZ3dXZ3eXh5dnR4eHV2eHt8e3l1d3d1dndz
dXV2d3Z1eHh0dXR2d3V0dnNxcXFvb29yc3FucnJycW9ycnBvbG5ycXF0cnNyc3Nz
cnFydHFvcHFycnNucXJvb3FzcHBxc3NxcG1ucG9wb3NxcXJwa2xtbXFwbnJtbnFv
b25uamtqbG1scHJwa25tbXBycG9tbW5vbnBvb2xtb2xxbmtsbGtpamtrbGtnamlq
a2pnaGhmZmptaGhoaGxqaGhpaGhpaWlpZmVkZWdoZ2lmY2RgYmhmamdlamdhYWNg
X2BgYmNhYV1eYWFmZGRkZF9cXWBgX19fY2NdYWFiYWJhXl5kYWJhXF5eX19hYmZi
Xl1gYmJiYV5iY2FhYmRhX2BlYWFiY2FfYWJhYmRjZGJeYmNmZGBhYmFaWVpaXFtZ
V1ZUU1NSVVVXWVNSUE5NT1JPTk1NT09OUlVOTk1PU1NRU1JTVFRRU1NWV1dXWlhb
W19bX11cX15fXFpeXV1dXV9fX15hYGBhZWJhX2FhYGBeXmFmZmJhYV9fYWFeXl1b
XFxcXWJgYGFgXV5eW1peX2BgYF5iY2RiYV9gYmFhX2BhYmNiYWBhYWJfYWFfYF1f
YWBgY19fXV5kYVlcX2FgYF1eW11gX15dXGBgX11hXltbW1teX2FdX15cW11cXF1e
X2BfYGRmW1tfYFxeYWNiX15dXmBcXF5gX2RfW2BjYmFhY19bWl9hXl9hYmBeYWVk
YmRiYmNjY2NjY2FjZGNgZGJjYmBfX19eYmJeXl1eXF5gXV1dXV1cXFtbW15fXV1e
XlxdW1xeXmBbWVpYVltgYF5dXV1eWVlbW1xZVlZVWFhcXl1aWllWWllbXVxbWFha
WFpbW1lZVldXVVZdV1daW1hYV1hVV1hTV1VUWFlXVVNVVVJSVVVWVlJWVlZWVFRW
U1VVUlVUV1RWUlJYVldXVFdcXVlYV1JQVVlTVVZXV1ZTU1dYV1VUWV5bV1RWV1pY
WFlbWldZWlpaWFdZXVlcXlpcXFlcWltfW1hZWltZXVteWFRSV1hZWlpZWFhXWFla
WFheWVtZV1laW1tcWFlcXF1eXVtYWlpbXF1dX1xbWltcXl5hYVtZWl5ZWVxeXV5d
XltaVlhaWVxcW1pbXV5eXlxdXV9eWllbW1tfXlxeXWBeXGFeXl5gX2BfXlxgY2Ji
YWFhZWJgXWBfYV9dXl1cX2BeXl9eXFtcX19gX15hY2NgY2NnZWFjY2FkZGJjZGJi
Y2BhYmNkY2NhYWJjZWJiYGJkY2BhZWVmYmRkZmVmZGNiX2FkZGNkZGJjZWRlZGJi
YmRjYmhjYGJmaGlmY2NnZWhlaWtramhmZmZqZGhpaGZnZmRnaGloZGhqbW9tamdp
bGtubGlsbmxpbW9wbGtra3ZoZGdpamhnZmhpaGhtbW1ra21qaGt+psnk8Pr+////
/////3ZnbnV6fHh2eHp7fHx6d3h3dXV6eHd5dXNzc3h5eXl1d3d3d3h2dnd0dXR0
d3h5eXh6dnV1cXR1dHV1dHR2d3h3d3p4enp5c3Z3dXV0dXl4dXV4eXt5dnZ0dnp5
eHZ4dnd1dnNzdHJ4fHx8eX16eXh2dnR0dHV2eHV0eXRycnB0cnNwc3dzb3FvcXNv
b3Fyc3Bxc3JwbmxucXJycnRzcXBwdHV1dnVzdHJvcnFycnZxcXFxcXJwb3BvcXRw
bXFvbXBubGpwcXFtbG5ub25xcW9rbG1tbGxta2xrcnRxcm5qaWxra25wb3Byc3Zw
b2xsbWtub21ra2xpam5tbG9ybGxrampramlpbHVza21maGxqaGhnaWxrbHBsa2tp
amhnZ2ZmZWViYGNjZmRjZWRoZ2VhX2JjY2JiYGFhYGBfY2dnY2FiY2BiX19fX2Fh
YWJgY2JjYGFgYV9dXF5fYFxfYWJkYmJeX2BiYmFiYGFkZGJfX19iZGlhYGBkZGJj
YmRlZWRhYWBhYmBcXV1dXVxbW1xbW1ZXVFBXVFNUUFRUUk5RVldQT1FPTkxMT1JR
UFFRUFBRU1NRUFBRU1RRUlRVUlNWWFhaWV1eW1tdX2BgXllYXV1bXWBgZWNgYV9g
X2JfX2JlY2VmZ2RmZWZiYl9fX19hX2BeW15hYF9dW15gYWRiXVlbXF9hYmNjZWBm
YmFdY2RkYWFhXV9gZGFhY2JeY2FeXmFgXl9iYl5dYGFcX15dYF5dXVpZXGBfXl1d
W19gYF9cXF1cXl1bX2JeXl9aW11cXF5fYGBhY2ReYF9dYWFjYmFfXlxcXVtdXlpe
X19lY2NgYWBeYmJdXl1hY2JiYl5fYGBhYmRkZGJjY2JjYmJiYGFiYmBfXV5eXV1g
Y2VgX1xbW1teXVpZW15fXVxeXVteW1lZW1pcXFxfW1tZWmBeWl1eXV1eXlxYWlxc
WlhZWFlYWFdbWltdWVlZXFlaW1xaWFdYXFtaWFhYVVZZWVhYWVdWVVZZWFxXW1lU
WVhVU1dXU1JVVVZYWVlaWllYWVZWVldWV1hWVlhXXllYV1ZYVlZVW1lYWFRUU1RX
VlZYWVlYWFhTWFZYW1xaW1lYWVtZVVZXWVpXWltZXFxaWFpXWV9fWltYVVhdWlla
WltZV1hYWVxbV1hWWFxbWl1cWlddWVlbW11aV1daXFlZW1xbWlpeW1pdW1lXW11e
W1tbXFhaXl1bX19cW1tcXF5cXF1aV15eWlpbWl5cXlxcWltcXFxbWlpcXFxdXV1i
X1tcX11gX2BhYWNhYF1eYmJfXmFnZWBeX2JeX2FfX2FjYWNeX2BfYmRkYWBfXl1f
YmNgX2BiYGFhYmNmZmZlZmRjZGVlZWZkYF9kZGNfXl9gX2BjZWVlYmJhZGJlZGJl
Y2JkZmRjY2ZnZGVkaGZlamJiYGRlZGNhY2hoZGNiaGVpZmtpZmBkZ2plYmRnaWdl
ZWdpZGZnaGdkZGlta2pqaGlnZ2RoamlmZ2pta2lqa2tqbG1sbGtqZmtsamhqbGlr
aGloa2dnbmpwZ2lra3uly+Hv+P7/////////cHR9e3x6d3Z3eX16eXh3d3p6dnh3
e3l0dnVxc3Z3dnd5dHV2eXh1c3N0d3Z4eXl8fXyAenl4c3RzcnJ2enZ2dnV0dnl+
e3d0c3V2dXR4eHh2dnZ1eHZ2dHh4d3V3dXR1dnZ1dHR0dHd3eX97eXl2d3R1dnd2
dnd5c3JzdXJ1c3Z3dXZ2eXRwc3FycHBwbnBvbnB3dXV1c3RwcW9ydXJzcnR3eHZ1
eHR0dXRzb29wc3FwbXBtb21ubWxtcnNxbm1rb3Fubm9ubm5vbmlqbmxpamxvbW1s
bm9vb3FycHJsamtra21rbW1vcG5xb25tbGlpbWttbmxsbGxpa2hoamtrbWxqamxt
bW9ub21rbnBoamdlZ2ppbW5tbW1vbmxqZWdmY2VlZGNjZWZlYmVjZGBiZGBfYmJp
Z2NkZWNgX2NjYmNhX15lZWBdYF5iXVxbYWBgYmJgYF5gX15cX19jY2BeXmBfYGJi
YV9gYmFfYWJjYF5gY2RiX2FdYWJlZGRkZWVmZ2NhX2FhXmNiXVtcXV1dXVxaWFZX
WFVUUlNTU1VTVVNVT05QUFFNTU5MTU9RT1JTUFBRU1BRU1VUVVVTU1NWVFZaW1pY
WlpaX11eX15cXVxdXlteXF5hZF9fX2BiYWFgXmBhYmJiZGVkY2RjYGBfXWBiXVxg
YWJhX19jYF9hYGFfXFpbXWJjYmFgYGFiYmNiY2VhXV9fZmNkYWFiZGNjYF5cXVtb
Xl5eX2RkZF9eXF5dYF5hXlxbXFlYW2FiY2JfYlxZXl5dXV9dXV5gXl1cW1tbWVpd
Yl9fYl9eY2FdXV5eXlxdXFtbXmBgYGJiYmhlX2FeXl5fYF9fX11fYGBiYGFiYWFl
Y2NiYmBiYWJnZ2FfY2NgX2JkYmNlYl9fYFxdXV5fXVxZWlpdXF1cYF9gX19eXlla
XWBiXlxYWFxcXVtdXFpfXmFgW1lbWlpYW1pbW1tZWFtdYF1aWVpZXWFfWFZUVlZX
WVtaWFZWWVZUV1dYWFVUVFZVWFxcXVtaW1hWVlVUU1ZXWVhbWFlWVFhaW1lYVlVU
V1pYVllZWFdaW1pYWFtVVlpcWlRUWFdXWVlWWVtbW15YWVtbXFtXWllWVVdZVlZY
V1hZWFlYV1daVVZZV1tcXF5cW1paWVheXl5dW1xcWVpbWFhXWllYW1hZXlpWXFxc
W15aWVpZWllZW15dWlxbW1lbXVxaXF5cXFpaWlpbXVtcXFxcXl1aWFpcYWNfXFxc
XF1dX2FaWVtaWVpbXVxbVltaWVpfXF1cYWBeYWFeX19dX2FfXmBfX2NqZGFfYGJg
YGBjY2VhYGFmZGFgYWJgYV9eXl5fYmNiYWJiYF9eX15gYGBiYGFjZGNjY2JjZmdj
ZGFhX2JfYGJhY2RjYWRjYmNiZGBkZmZmZWRkZmVmZmVlZGlmZ2lpaGZmZWdkZWRl
aWhjY2FjZmNmaGlnZmtqZ2dkZWdkZWVkZGdkZ2hpamhoZ2ltZmZnZWVlY2dpamtr
a25wbWppbW9vcHFxb2xxbGxva2xoamlpaWprbGprb21mZ2h3gqDN4u/3/f//////
//9ueHx9fnx5eHl8eXp7fnl4eX14e3l5d3l3dHV0dXZ4dHZ1c3N0dXRzdnR3eXd4
dHV6e359eXd4dnZ5d3d3dXZzdHZ0eHh3d3h3dXh1cnB0c3R2d3Zyc3R4enp3eXh4
dnd2d3p7e3x6dXh2eHd2dHd5dHR0dXd5d3V0dXR1dHRzdnZ3eHhzdHd4eHJxbmxu
b29wcnJzdnV0dXBydnNxcHFwcnV2dHd1dHV3dXRycnRzdHFtb3FxcXBubm9wbG9w
b29vbnFycXBsbW1xc3Jtbm9ubW9ubWxtb25wdG9tbm1wcWttbW5sbWtwbnFsamps
bGtoaWtvcW9tbGxsa25vbWtoaWtsa2psa2tpbWxqbGloZ2loaWtsbG5tbGxraWlq
a2lnZWVlY2JiYGJnY2JkZV9hY2JjYmBga2dhYWNkY2ZkYWBfXmBgXlpdYl9bW11h
ZGRhX19fXGFcXWFfX19hXmBhYGBiZGZlY11cXWNkY2ZmYmJgXl9eXmFhZGFjY2Nm
Z2hmZGJjYl9eYGNhXl9eXFpcXVxbXFhWU1FRUlNSUE1OUFFNTE1NTUxPT0xKT1JY
U1JSUE9SVFZTUlJTVVdZWlhZWlhZWVhdXF9hXV9cXVxeYl9dYWBdXV9gYl9fXmBg
ZGNfX2NjY2NkYl9jYGFjY2FfYV5gYV9gY2JhYV9lXWBiXmFjX2BfXV9eXF5dX2Bf
ZWNkZWhmX19dYF9jYmFfY2NhXF1dYV1dXFxdXl9gYGFdXGBeXmFhXFtdXVxcXl5g
YmFeXVtcYGBcXl9dYFxfXl9fXl9eXV1eYWBeXVxdYGNhX2FfYWFgYV9eYGNgYWJj
X19gX11cXl5dXl5hX19hYWFkZGJiZGNiYmJjYWFjY2FfXmFkY2RlZmdhX2BhXmBi
ZGRiY19dXVxZXF1eXV1gYV9eYl5hX19eX2JdWl1cXVxcXmFeXF5eXV5bXmBkXFla
WFtbWltbWllbW1hbWVlZWltZW1hXWFdaWlpZW1tVVldYV1ZXWFRWU1NWV1hYWVpY
V1hWVlRTV1ZXVlVTUVNaVlVUWFdVVVNUWl5bWldYWFpbWlhZV1ZYVldcWltaWVdY
WVdVV1lbW1hXWFpXVVZWVlVUV1dZVVVVVVZVWFpXVlhaWlpYWFtaXWFdWllZWltb
W1pbW1lYWVxZWFhUVlhZXF9bWVtYXFxcW1pdXV5YWFlXWltcWldaWVlbW1pXV1pa
W15hXVxgXVlZW11aW1laW11bXF1ZWmBcXFxdXF9cX15aWlpZXFteWl1gYl9hW1la
Xl1eXV1eXV9dXl1dXV9hYGFhX11dX2BgX2RlZWNlYl9hYWNgX2BfW1tdXV9iZGJg
YF9gYGNiYGFjZ2FgZGFgYWVhY2ZkZWdgYGBmZGFgYWFiYmBfY2RlZWRkZGVkYmVn
Z2RnamdoZ2VjY2ZnZGJiZmplZmVlaGNkZ2ZmZWFiY2ZmZ2trbGtpZ2hqa2xqaGZn

View File

@ -0,0 +1,120 @@
5eXl5uXk5eTl5eXl5eXm5eXl5eXl5ebl5ufl5efl5ebm5+bm5ubm5ebm5ufm5ufm
5uXm5+bl5+bl5ufm5+bm5ebn5ufm5ubn5+bm5+bm6Ofn5+fm6Ofn5+jn5ubn6Ofn
5+fm5+fn5+fn6Ofo5ujo5+fo5+fn6Ofo6Ojn6Ojn5+nn5+fn5+jn5+fo5+fo6Ojn
6Ofn5+np6Ofo5ufo6Ojn6Ojn6Ojn5+no5+bn6Ofn5+fn5ufn5+fo5+fo5+fm6Obn
6Ofn5+jo6Ofo6Ojn6Ojo6Ono6eno6ejo5+jo6Ojo6Ono6Ono5Ofo6Ono6ejo6Orp
6ejp6enp6Ojo6Onq6Onp6ejo6eno6enp6eno6ejp6Onp6enp6unp6eno6Onp6unp
6ejp6enq6ejp6unp6enp6Ono6eno6uno6enp6Orp6enq6uno6unp6enp6erp6Orq
6Onq6eno6unp6unp6urp6urq6enp6urq6uno6urp6erp6erq6urp6urq6erq6uvr
6erq6enq6ejq6urp6uvr6erq6urp6unq6unq6Orp6+nq6unp6err6unp6+rp6urp
6ejq6erp6enp6erp6erp6eno6ujp6unq6+rq6urp6+vq6uvr6urq6urp6+rq6urr
6+nq6unq6urq6uvr6+rq6uvr6+rq6uvq6+rr6urr6uvr6+vr6+vq6+vr6+zr6+vr
6+zr6+rr6uvr6+rr6urq6+vr6uzr6+zs6+zs6+zr6+zs7Ovr7Ozr7O3r7Ozs7Ozs
7e3s7ezr6+3r7Ozs7e3t7O7t7O3t7ezt7u3t7u3t7u3t7+/t7e7u7+7u7+3u7+7v
7u7u7u7v7+/w7u/v7/Dv7+/w7+/v7u/w7+/w8O/w8PDw8PDw8PHy8PHw8PHx8PLx
8fLx8vGVjoV7dW1kYmJYVlRVVFRWVldZW1xdYGJjZmlqbG5wcnZ3en1+gYKFh4qL
jY6OkZKTlJaXmZqdnqGjpqipq6yur7Gxs7S0tLa2uLm5u7u9vr7AwMHCw8PDxsbI
ycrJy8zNz8/S09PU1dfX2dnZ2dja2tra2tvb2tra2tvb29rb3Nzd3d3d3t/e3d/f
3t/f39/f197f39/f3+Df39/e3t7e3t/f3d7d3t7e397e39/e3uDg4ODg4OHh4ODg
4d/f3+De3uDf39/g3d7d3Nza29va2tja2tnZ2NjW1tjX1tbW1tXU1dXV1dXV1dXV
1dXW1dTT09PS0tLS0dHS0NHR09PS09LT0tTU1NPT0tPT09TS09PT0tLR09PT09PT
09TU1NTU1NTU1dXV1dXU1dXV1dXV1dXW1tXX2NfX19fX2djZ2dnZ2drZ2tvb2trb
29vc29vb29vc3Nzd3N7d3d/e3d7e397f3t7e39/f3uDg3t/g4OHg4ODh4d/h4OHh
4OHh4eHh4eHi4uLi4uLj4ePi4+Li4uPj4+Pi4uPj4+Pj4+Ti5OPj4+Xj5eTk5OTk
5OXj5OTk5OTk5OTk5OTj5OPj4+Tk5OTj5uXl5OXl5OTl5eTl5OXl5ebl5ebk5eXl
5ubk5OXn5ubl5eXl5uXl5+Xk5eXl5ebl5ebm5ubl5uXm5ufn5uXn5ubn5ubm5+fm
5ubl5ubn5ufm5ufm5ujn5ubn5+fn5ufm5+jo6Ofn5ubm5+bm5+fn5ufn5+fo6Ofo
5+bn5+jn5ujn5+fn5+fo6Ofo6Ojn6Ofo6Ofn6Ojp5ufo6Ojo6ejn6efn6eno6ejo
6Ojo5+fn6Ojp6Ojo6ejo5+no6Ojo6Ofo5+fo6Onp6Ojn6Obn6Ofm5+fn6Ojn6Ojo
5+jo6Ojo5+jo6Ofo6Onp6Ojo6Ojn6Ojo6Ojo6eno6ejo6enp6Ojp6ejp6unp6Onp
6enp6Onp6Onp6eno6Ono6enp6enp6Ono6enp6OXp6Ojq6ero6unp6unp6enp6unp
6unp6eno6enp6urq6enp6enq6unq6enp6erq6urq6unq6unp6Orp6enp6erq6erp
6erp6urq6urq6enq6+rp6urq6unp6ujp6unq6enq6evq6unq6unq6uvq6unq6urq
6+vp6ujq6unq6urp6unq6unp6+rq6evq6urp6unq6+rq6urq6erp6urr6+nq6urp
6unq6+nq6erp6erq6erq6erp6urq6urq6evq6enp6enp6ero6unq6+nr6urq6+rr
6urq6uvr6urq6+vr6+vq6+zq6+vr6+vq6urr6+rr6+vr6urr6urq6+zr6+rq6+vr
6+vr6uzt6uvr6+vr6+vr7Ovs6+vs6+zs6+vs6+rr6+rr6+vr6+vr6+vr6+zr6+zt
7Ozr7Ovr7Ovr6+zt6+zs7e3t7O3s7O3t7ezt7O3t7ezs7O3u7ezt7O3s7u3t7e3u
7ezu7e3u7e/u7u3u7+3u7u/u7u/v7u/u7+/v8O/v7+/v7+/v8PDv7/Dv7+7v7/Dx
8PDw8PDx8PHv8fHy8PHw8fDx8fHw8fHy8vLy8qOdlpGLhH56dXRycHFxcnR1d3l6
fH+ChIeJi42PkpSWmZyfoaKmqKqrra+vsLK0s7W3uLm6vL2+wMLExcfGyMrKzczN
zs/OztDQ0tLT09TV1tbW1dfY2NfY2dra2trc3Nzd3N7e3t7e39/f39/f4ODg4ODg
4eHg3+Hh4eDg4OHg4ODh4uHh4OHh4uHh4eHj4eHi4OHh4uHi4eDh4eHg4eHh4eHi
4eHg4eHg4eDi4eLg4eLj4+Li4+Li4+Hi4eLg4eHh4uHi4uLh4OHg4eDh4N/e4ODf
4ODf397e3d/f3d7f393e3t/d3t7d3d7d3d3d3d3d3tze3d3c3tzb3d3d3Nzc3N3d
3d3e3d3d3d3d3d3d3t7e3tze3d3e3d3e3dzf3d7e3d7d3t7d3t7e3t7e3t7e3t7f
3eDg3+Df4N/f4ODf4N/g4N/g4ODh4OHh4eHg4eDi4eHi4OHh4uHh4uLh4eLi4uLj
4eLj4uLj4+Lh4uPj5OLj5OLj5OPk4+Tk4uPj4+Tj4+Ti5OPk4+Pj5OTl5OXj5OTj
5OPk4+Tk5OXk5eXl5eXl5ubm5eXl5eXm5uXk5eTl5ubl5eXk5Obl5eTj5OXl5OTl
5uXm5ubl4+bl5uXl5ebk5uXl5eXm5uTm5ubn5ubm5uXn5ubm5ufl5ebm5uXm5+Xm
5ufm5+fm5ebm5ubn5ujn5ubl5ubn5ufn5ufn5+fn6Ojn5+fn5+jn5+fm5ufm5+fo
5+fn5+nn5ufn5+bm6Ofm6Ojn5+jo6ejn6Ofp6Ojo5+jo6ejo6Ojn5+jp6ejo6Ojo
6eno6Ojo6Onp6efn6ejo6Ojo6ejo6enp6Ojo6ejo6eno6ejp6eno6ejo6Ojn6Ono
6Ojp6enp6Ojp5+fo6Ojn6Ojo6ejo6ejo6enp6Ofo6ejo6ejp6Ojo6eno6ejp6erp
6Ono6Ojo6eno6eno6enq6erp6uno6ero6Orp6unp6erp6unq6unq6urp6uno6ero
6Orp5eno6erq6urp6unp6erp6Onr6erp6+nq6unq6enq6+nq6urp6urq6erp6urp
6urq6urq6urq6urq6+rp6+rq6uvq6Orq6unr6urs6urr6urp6unq6urq6urq6+rq
6erp6urp6urq6urq6urq6err6err6+rq6+rr6urq6+rr6urr6urq6+vq6uvq6+zq
6urr6uvr6+vq6+rr6urr6uvq6uvq6uvq6+vr6urq6err6evq6uvr6urr6urp6urq
6+rq6unp6urq6urq6urq6uvq6urq6+vr6+vr6+vr6uvs7Ovr6+rq6+vq6+vq6+vq
6+vq6+vr6urr6+zq6uzr6+zr6uvs6uvs6+zr6+zr6+zs6+vr6uzs7Ozs6+vq6+zr
6+zs6+zr6+zs6+zs7Ovr7Ovs7Ovs7Ozs7Ozs7Ozs7O3s7Ozs7Ozt7O3s7Ozs7u3t
7e3t7O3t7e3t7e3t7u3u7e3u7e3t7e3t7e7t7u7u7u7u7u3v7u3v7+/u7+7u7+7w
7+7u7u/w8O7v7+/w8O/x8PDv8PDw8fHw7/Dv8fHx8fDx8fHx8fHx8fHw8fHx8vLy
8vLxs6+qpqGcmJWRkI6Oj5CQkZOVl5mbnaCipKepq62wsrS2uLu9vsDDxMXGx8jI
yszNzc7P0NDS0tLU1dXY2NjY2dnc3Nvc3Nzc3Nzd3d3d3t7e397e4N/f39/g4eHh
4OLg4eHh4eHi4eLh4uDh4uHi4eLi4uPi4+Hh4ePh4uHi4+Lh4uLj4uLi4uPi4uLj
4uPi4uLi4uLi4+Pi4uPi4uHi4uPj4uLj4uLi4uPh4eLi4uLi4+Li4+Pj4+Li4+Pj
4uLi4uLi4uPi4+Lh4uHi4uLi4uPi4eHi4eDh4eHf4eHh4eLi4OLh4ODg4eDh4eHh
4eDh4eDh4eLf4eHg4N/h4ODi4ODg4OHh4eDg4OHh4eDh4uDg4uHi4eLg4OHh4eDh
4OHg4uHh4eHh4eDg4eHi4eHi4eHi4eLh4uLi4uHi4uLi4uPj4uPj4uHi5OPk4+Pj
4+Pj4uPk5OLi5OPj4+Pk5OTi4+Pj5OPk5OPj5OPk5OPk5OTk5OXk5OTk4+Tl5eTk
5eXk4+Tk5OTk5OXk5OXl5eXk5eXm5eXk5OXk5uXl5ebl5uXl5ubn5eXm5ubl5ubm
5uXl5eXm5uXm5uXl5eXl5eXk5eXm5uXl5ubn5ubl5ubl5+Xm5ubm5ubn5ubn5efm
5+fm5ubn5+fn6Ofn5+fm5ufo5ubn5+bm5+fn5+fn5+fn5+jm6Ofn5ujn5+fn5+fn
6Ojo6Ojn6Ojn5+jo6Ofn6Ofo5+fn5+jo6Ofo5+jn5+jn5+jn5+jn6Ojo5+jo6Ono
5+no6Ofo6Ojo6Ofp6ejn6Ojo6Onn6Onp6enp6eno6efo5+jo6Ono6Ojo6enp6Ojo
6enp6enp6Ojq6Ojo6eno6Onp6ejp6unp6ujq6unq6enp6Ojp6Orp6Onp6enq6enq
6eno6Onp6eno6ejp6eno6Onp6erp6ejq6eno6erp6enp6enq6urp6Onq6unp6urp
6+nq6enp6enq6unp6erp6+nq6enp6unp6enp6erq6unr6uvq6erp6+rp6erp6unq
6urq6urp6urq6err6uvq6urq6urp6+rq6uvr6uvq6+rp6urq6urq6uvp6+nq6urr
6unq6+vq6+rr6urq6urq6uvq6urp6urq6urr6urq6urq6urr6+rr6urq6uvq6urr
6uvq6erq6uvr6+rr6urr7Ovq6uvr6+vr6+vq6+vr6+rq6+rr6+vr6urq6+vr6uvq
6uvq6+vq6+zq6uvr6+rq6uvq6+rq6urr6+vq6urq6+rq6urq6uvr6+vq6+rq6uvr
6+zr6+vr6uvr6+vr6+vs6+vr6+vr7Ozr7Orr7evr6+rr6uvs6+vr6+rq6+zs6+vs
7Ovs7Ozs7Ovs6+zs7Ozs7Ovs6+zs7Ovs7Ovs6+zs7O3s7Ovs7Ozr7Ozr7Ozs7Ozs
7O3s7O3s7e3t7Ozr7Ozs7uzt7ezs7O3t7uzs7e3t7uzt7ezu7e7t7u3u7u7u7e7u
7e7u7u/u7u/v7e/u7+7v7+/v7u/u7u/w7+/v7u/w7vHv7u/v7vDw8PDw8PHx8fHx
8PDw8fDx8PLx8vLx8fDw8fHy8vLy8vLy8/MAEAEAAAMAAAABBJcAAAEBAAMAAAAB
Bt4AAAECAAMAAAABAAgAAAEDAAMAAAABAAEAAAEGAAMAAAABAAEAAAERAAQAAAAQ
AB+FwAESAAMAAAABAAEAAAEVAAMAAAABAAEAAAEWAAMAAAABAG8AAAEXAAQAAAAQ
AB+GAAEaAAUAAAABAB+GQAEbAAUAAAABAB+GSAEcAAMAAAABAAEAAAEoAAMAAAAB
AAIAAAFTAAMAAAABAAEAAIdzAAcAAASkAB+GUAAAAAAAAAAIAAH9gQAD+voABfhz
AAf17AAJ82UAC/DeAA3uVwAP69AAEelJABPmwgAV5DsAF+G0ABnfLQAb3KYAHdof
AAH9eQAB/XkAAf15AAH9eQAB/XkAAf15AAH9eQAB/XkAAf15AAH9eQAB/XkAAf15
AAH9eQAB/XkAAf15AAGq2yWAAAAAIAAAJYAAAAAgAAAAAASkYXBwbAIgAABzY25y
R1JBWVhZWiAH0wAHAAEAAAAAAABhY3NwQVBQTAAAAABub25lAAAAAAAAAAAAAAAA
AAAAAAAA9tYAAQAAAADTLWFwcGyYcjd2/nI/x5EwPxA3BfUzAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAVkZXNjAAAA5AAAAEF3dHB0AAAAwAAAABRrVFJD
AAAA1AAAAA5jcHJ0AAAEYAAAAEFkc2NtAAABKAAAAzZYWVogAAAAAAAA81EAAQAA
AAEWzGN1cnYAAAAAAAAAAQHNAABkZXNjAAAAAAAAABVTY2FubmVyIEdyYXkgUHJv
ZmlsZQAAAAAAAAAAAAAAFVNjYW5uZXIgR3JheSBQcm9maWxlAAAAAG1sdWMAAAAA
AAAADwAAAAxlblVTAAAAKAAAAw5lc0VTAAAAMAAAAYpkYURLAAAAPAAAAjZkZURF
AAAAOgAAAeJmaUZJAAAAMgAAAMRmckZVAAAALgAAATBpdElUAAAALAAAAuJubE5M
AAAAKAAAAnJub05PAAAAKAAAAbpwdEJSAAAALgAAArRzdlNFAAAAOgAAAPZqYUpQ
AAAAGgAAAV5rb0tSAAAAGgAAApp6aFRXAAAAEgAAAXh6aENOAAAAGgAAAhwAUwBr
AGEAbgBuAGUAcgBpAG4AIABIAGEAcgBtAGEAYQAtAHAAcgBvAGYAaQBpAGwAaQBH
AHIA5QBzAGsAYQBsAGUAcAByAG8AZgBpAGwAIABmAPYAcgAgAEIAaQBsAGQAbADk
AHMAYQByAGUAUAByAG8AZgBpAGwAIABHAHIAaQBzACAAZAB1ACAAUwBjAGEAbgBu
AGUAdQByMLkwrTDjMMowsDDsMKQw1zDtMNUwoTCkMOtjg2PPVmhwcJaOgnJfaWPP
j/AAUABlAHIAZgBpAGwAIABHAHIAaQBzACAAcABhAHIAYQAgAEUAcwBjAOEAbgBl
AHIARwByAOUAdABvAG4AZQBzAGsAYQBuAG4AZQByAHAAcgBvAGYAaQBsAEcAcgBh
AHUAcwB0AHUAZgBlAG4ALQBQAHIAbwBmAGkAbAAgAGYA/AByACAAUwBjAGEAbgBu
AGUAcmJrY89O6gAgAEcAcgBhAHkAIGPPj/Blh072AEcAcgDlAHQAbwBuAGUAYgBl
AHMAawByAGkAdgBlAGwAcwBlACAAdABpAGwAIABTAGMAYQBuAG4AZQByAEcAcgBp
AGoAcwBwAHIAbwBmAGkAZQBsACAAUwBjAGEAbgBuAGUAcsKkzpCxCAAgAEcAcgBh
AHkAINUEuFzTDMd8AFAAZQByAGYAaQBsACAAQwBpAG4AegBhACAAZABlACAAUwBj
AGEAbgBuAGUAcgBQAHIAbwBmAGkAbABvACAARwByAGkAZwBpAG8AIABTAGMAYQBu
AG4AZQByAFMAYwBhAG4AbgBlAHIAIABHAHIAYQB5ACAAUAByAG8AZgBpAGwAZQAA
dGV4dAAAAABDb3B5cmlnaHQgMjAwMyBBcHBsZSBDb21wdXRlciBJbmMuLCBhbGwg
cmlnaHRzIHJlc2VydmVkLgAAAAA=

View File

@ -0,0 +1,136 @@
TUxOT1JVUFNUVlVRT1VYWVdXUlJUT1FPU1VPT01PUE9WVlFSUFJRTkxKTU1PTEtJ
R0JDR0RDQEBBQD8/PDs/PD0+Pz44NzY1NjY5ODw5OT08Nzk5ODs8QUNBQj9BQUND
QklLSk5KSU9TXlhLT0xWUlFaVFdMTVdVW1VgWVdWXV9dWFtWUlFSTkVERTk1NTUz
MzUzNjU0ODg1ODY2Nzk6PTo6P0NETE1JR1RSTFBISkpKVVVLSUpUTU5STVZRVFpT
Vk5XXGBYUFhVWFJTV19kXVdVUFdVVlZUW1xbWlhZV1pcWE9TWlRWWVlXUE1MTlJD
PDo8Ozo+P0pOTVhWVFJWW15oYFxbXlpUVlpZXFhYVVdXUFlcYFhUVFdaW1RQXVxc
XltXUVBSTU1RUVRYVVNNSU1RUFFWVFFST05QUk9OSU5QTk1KS1BVSkxLTE5LT1RO
VlRZWlZYVE1FRkVHR0ZLSU9LTlFOXWaJo7CspZ2WlZOJfXFmYmFqdG9eS0E+OTk4
ODtBQTw9Ojg5PD5EQT8/P0BAPDc6OEE+Pzo+QENAPDtBQENDRkNDR0A6QEQ8ODU0
MTQ3NTg3Mzc2NDg0OTs/RUpTS05JT1xYWVlUXFZWVVtdWVlXUE5TUlJQT1BUVlZR
VFVYW1NRTkxMUlZUUEtMTk9PTE1MSERESUpLSkxJRklJSUtLRkRJSEVCRENERUZE
QkNBQ0JEQ0FAPjk6PDo3OTc3ODU2ODY2NTc+Rk9YYmdqaGhna3B3e3x+gYGBgYaH
iYuKi4uKioWCfXdwbmpnaWlsb3eCiIuMjYmJjo6SkJCTl5ORjIaBfnZnVEc/Ojo6
ODo7P0RJSkxPUlVWWVhWVlVSVFFRT05JRkVARD5BPkBCRERDQ0ZGRUdFSUpKSkpK
SklOS0xNTkxOT05MS0tMTk9NT1ZWU1dZWl1eXWJkZ2hqbm91dXV4fH5/gYB/gYOC
hYmGiIiHh4iGh4qLi4qMjY2Li4uLjZKTlpeWlpSPjo+SkZOQkpGRlZiXlpaZmZuZ
mZibl5mZmJiampual5aYnKCpr7KqmImGiJWosbzAvLu5u7i1tbGwsbKzt7a8vcC/
vL29vr6/v7q8vLq8vrq4ube1tLe3t7S0ta2ysrK1tKyginBfXVhTUlBOTVBMTU9M
S0tLSUpLSkhJSkdPT05KSUdNS0lJSE1LSkxKTk9MTUtNSk9OTUxPUU5NUE9OT0xM
Tk5QUVFQUU9QUVJSVFVSUlNTU1JRTlJTUFBSVFRSUlFTT09RUlBSUVNTUU9QUVNV
VVVVUVFSU1FVU1JSUFFSU1hUUVFPUVRQUVJRU1NUVVZYWFZWWlhYVFFVWFhXVlhW
WFhaWltbWF5bV1dYVlhbWFZYWVlaWVlYV1laWVpZV1taWVlaWlpaWVtcXV1cXF1d
YF9dYF5dXV1dYF5bXV1cWlxWV1dYV1ZWWFdYV1ZZXIO9ydPa3uHk5efo6el7enh5
ent8eHd1dnl2dnh6enl4eXdwZ1pMR0VFSkVEQz09Q0hKQ0A/P0I/PEJCQT4+PTpA
RURFQ0RHQ0RBPT5ARkhJSkxMTk1JS05QTklKTk5QUVNUU1FXU1ddWVVRUFFTU1JQ
UlBQT0tRVVVVU1JSUFJNSktPT0tJSUhHREVFQ0dEQkNAPj0+PTw7Ozs6OTw2Nzk4
ODg6PDs5OTg3Nzs4Ojw7Ozw9PURBQkQ/RktGS0tISUpRVU5RTUpTT1lTV1VOVlNc
WV1cWVddY1xdXllPT1JVT0pAODc1MzU5Njc6OTs3Njg2NTc7ODg4OTg+Q0dPUEpH
VVRMUUxRSkpUTklOSVNSTU1KV1RSWlFYVFRVWVdNUFJeVFRVYWFdXVZQUVVYV1VZ
VFdYWVhZXGVhVlRbW1pXUU1LTFBMTkhAOTg6OTk7Q1BSVVldWFpeXmFhY2VjXlNR
U1BXWFVVUVZYWFdWU1NTVVZaV09WWVlaWlNQTUtOUE1OUlhZVFFXUE1NUFBQTlFS
UFJWTU1OS0pRSkVJUFBNSkpNUEtPVFVXV1lXVldXU0hGRUdJSVBJSUhOVE9RWnWU
qauroZiVkYl8c2xmY2VrdWlSQTs6Ozg7OTw8Oz08PDw7Ozw7PTtAPj09Pj1BQUJA
OTo+QUQ9OD1FQUM+RUJCOzY9Q0E4ODU0NDY2NjQ0MzI1Njg4Oz1ESkpISkpTWlhY
W1ZZV1hTVldOUVNOTE5OUlFQVFlYU01XV1dWU09MSktOUlRTUU1PT0xQTklFR0ZL
TU1LS0dHR0dJSkpGRUNGSExHQ0RDREVBQD9APz5AOzs+QD88Pjw4NjY0Njc5Nzg7
QUpTXmRmaGdoaGxwdHp7fXmBh4eHhoyQj5CNjYuJhYJ8dnN1b2xtbGtze4SJjI6M
iImOj5KUlpWVk5GQi4B3a11RRj5APkFAQUFCSEpLTVBQU1hYWFZWV1NRUlBQTkxJ
RkdDQT5AP0NDQkNARERJR0lJRkhHSUtQUE1MS0tNTExNTE1NT1FSUFBVVVVXWF1f
XmNjZGdsbG5zdXZ1dnt9f4CDg4F/goOFhYaGh4uHhoWJi4mKi4mIiouNjIuMkZGR
lpSUj5GQkpKSkpWTkpaXl5OVlpmbmpiYmZmZmJqWlZeYl5iZmp+jqrO5s6aTgXeB
mK64vby7urq9ure0srSztba1t7m9vsDDwr69vb+9uru+wL69vbi3tbSztbq1tLe4
rrOztrW1saylknplXFZUVVNPTU9PTk5NTU1NSkhISkpJR0lKS0lKUEpKS0xPTVBL
TUxKS01KTExMTkpPTktQUE5PT09QTU5NUFBSUlNST1BPT05ST05PUVFTVlJSU1NS
UlRTUVJTUVBRUU5RTlFSU1NQTk5NUFVTUlBSUVBRVFRTU1NSVFJQUlVUVlNUVFFS
UFNVU1JUVVVWVVZXV1VWV1dWVVVYWVhZW1pYWVtdXF5aW1hZWFZZWVhYWlpYV1dY
WFZXW1tZWFlYWVhWWVlZXFxcW11cXltcXltdXlxdX19dXl5bXVtbWFlYV1VXV1ZU
VlVVVVdgfLvJ0dre4eTm5+jp6nl7e3x7eHp6dnh5dnd4dXd4dnZ5cmlgUkhCQEJH
QEM/PkFCRERBQERDQz4/QkU7PD1CPkBBQUFAQEFDR0I9PENCR0dISEdJTklMT01P
UlFNUFBRUlJZVVVWV1ZUU1hSVFZVUlJTUlBRUVNTVFVSUFFOUE5NTExPTUtIREhH
RENDQkJFQj5APkE/Pz87Oj08Oz04Nzc4NzxBODQ1Nzc4Ozo6Ojg2OTs7Ozs+QT9D
SUdISEZGRkpQS01LRElHTEpLVVRaWVhZXFtZVlhgX1xXV1BVblVUSkA5NzQ1NDc1
NTQzNDQ0NDg1Njc2NTg7PD8+PkpJTUZNT0dPS1JNSFBLRkxIS0hLSk1UVFlgVl5X
UVJUVUxRT1ZVUlFZXVpWVFJTVllZV1dUVFtaWltfZl1VWFtcVlZVT0tTUElIR0Q5
NzY3Njk/SVJWWmxlWlxdWWBpYV9kV1JUUVJcWlhTT1NSV1pTVFNTVlVXVlZVWFJU
WlNPS01VVVpaWVVYV1VWUU5QTk5PUFVRTE1LS0xIRU5KSEpOTk1JR01MSVBVWlxT
VFhcWFpZTkdDQEFFS0VISElTUU9WYniWpqiooJeOhn92a2NgYGZwbV5JOzs/QkI7
ODs9OkA+PDw6OT1APj4+SDw6Oz4/QkA7O0A9Pz5CPDs8QTxDQkJJPzpBPzo8Ozg2
NzQ3NjczMjQ2Nzg7PT9HS0RJR01SUldSUE9OT01VWFJWVE5LTlFTUlBSVldSVFhW
VFJWUVBNTEhLTFJUTExNS05OSUZITE1LS0pKT0pGREVGRkdIRklKSUlERURCQ0NC
Q0E+PDk9QD9BPzw6ODo4OTo9Ojg5PUdQW2VqamlrbWttcnd6fH19fYKDiI2Ojo2N
jo6LjIiIhX58eXVzcW9sb3d/hIyOkI+Lio6QkZOYlpSTjYuHgXJkWE1IRD89QEJF
RUZMT0xPUVNUVlhaW1lXVVNSUlJPTUtNS0dDQUJEQkJDRUZGR0hFR0dHQ0dHSEtI
SEtJS05LS0xSUVNQTlFUUlVZWFlcXWFlZ2hsbW9zcnV8fH9+fX+AgYGBg4SEg4KD
hYOCh4eHh4eJi4qKi4uOjI2KjpGSlZWUmZaSkpeWkI6TmJWYmpiXmJiampuXnJmY
lpaZmJqYmZmbnJ2jrLGwsbSwopSDfIeXrLu/vr28urq4s7OzsrK0trW3ubu8v8G/
v7++vr27ur27vLy7ubW2uby7t7e1ube1tbe2tLW0sa+mmIFmWldXUlBRT0xOS0xO
TVJPTUtKR0lKTEpKTUpJSUlLTUxJTE1PUExJS0tNS0xOTU5MS0xLS09PUVFTUE9R
UFNSU1FRVFJNT09OTlBQUlNSUVBRT1JUVFFPUVRUUVNRUE5QUVFSUFFPSk5RUE9P
UVNTVlFRTFBPUVJSUlJRT09SUlBQUE9RUlJTVVVTVFVWV1ZYWFZYV1hVVVRTV1ta
W11bWVxaXV1aWlpcWllZWllaXV5bV1dXWFpZWldXWVpZVlVXWVlbXFxaXF9cX11f
XFxcX15iYWBdXFhaW1pfXFtZV1RWVllXU1NXW2Z9usjT2d/h4+bn6OnpeXp7enl7
d3t7enl6eHp4eHl1dG9rZFtRSkdDQkBAQUY/PEVESUREREM9QUFEQUVBPT9BPT8/
Pz8+QT5BRENHQkNFRkhJS0xNTkxQTE1SU1NQUlNRUlVWVVVZWlZVU1VWU1ZWVFJQ
VlJPUFNXWFZVU1RUUFFPTkxISEdJTEpGREJCQUBAQENHQj07PTo8OzU5Nzc4ODg3
Nzg1ODk4ODc5Ozg6ODk3OTk4PD5FQj5AQEBFREU/QlFPSklIR0dHSkxUU1xZUVVZ
YFhPU2BaV1RYUU9UWFZKQDo3NzI0NTAyNjQ0Ozg4Njc2Nzk5ODw6Ozo+S0ZLRUdF
Q1RMWlVMUU9KT0pPTFVWSlVTVFtTWlNUVlJSTFNOUlRQSlRUWVdaWVVSUldZWlVT
U1dUU1pdXFZXW15VVVVOTldSTUdHRzo2NzU2OTk+TV1eYmJYX11aYGleX2lYTVJR
Vl5gXFhRUVNYXFJSWl1ZVlFWWlJSU1JcVVhTTlhYWFNTU1lYVVhSTU9RUVRTT05F
SEhJRk9NS01OTU9KS1FJTFFRUlNUV1FTV1xdX1lRSERBQkJHRkpJRVJRU1dVYnqW
pKekno+Jg3pybWhkZW1yZ1BEPDw+PTs3PDpEQ0E9Ozs7PDs/PEdCOjk9Oz1AQkA9
QEFEQj06Ojw7PT9ASUhAPEFCPDg4OTczNDM2NDQ1MzU2ODk6PD5FRk1JUE5WXlJU
UkxMTFVVT1BSUFRVVk5ISlNVVVRWWFRUVltYWE9LTUtKSkxJSUhLTU9NSUlMTkxI
TU9NR0NHSElLS0xISkhKRkNBQ0RCREJCQz49PDtAPjw6ODg5PDs5Ozg2OkBLWGNo
am1tbWtubXB1enp7e36Bg4aGiZKRjo2NjY2LiIiFhoKCd3Vua25vdH2DjI6NjIyO
kpGQkpOVko+NiYN4aV5XU01LSUI+PUNHTFFSU05RUlVUWVtcXFZUUlFUU1FPTkxK
R0ZCQUBAQUFEQz5CR0pIR0hESUhHRElKSklLS05MUFJVU1JRU1VaWFxdX19iY2lr
bW9ycnR3enp5e318fX9/gH6Cg4SFgIOFhoeGh4mMiouOjo6PjY+MjY2RlJKSlJuX
lZSUlZaQkpKWl5qTk5aYmpqbm5yampyam5mWl5uenZ+lqK2ytby9tqmcmJiRjJit
uL6/vru6uLKuq62vs7a2t7e6u73BwcHAwcG/vcC9vLm4u7e4t7i4ur29urq4tre6
uLa5trWzs62onohtXFVUVFJRT01NS0tKS05RS0tKS0xPTklJS0pJSUdLTEtJTEpO
S0tHSUpNT05QTk5LS0xQTlBPUFJRTVBRTk9OT05PUlJPUlBQTk9QUFFRT1FRVVNU
VFRTUlFWU1JQU1JRUFNVV1RPT1BRT1FSUVNUU1JOTlBPUFBQU1RSUVBSUVNSUVNR
UVNVVFRTVVRWVFJTVlhXWVdXU1NTWFtbWl5dXFlZWFhZWFxYVlpYWFlbWVpZWVZX
V1dYWVhYWFdXVVRZW1pZWlxdW1peXl1cXGBgX19gYV9fW1pZW1lcW1hWVFVXVVlW
U1NVaoS8ytPa3uLk5+jo6el4eXh1eXh9eHt7e3t4eHZ1eHh0cm5jWEtLTEY/PTs8
P0NGSklGREVBOz0+RD9BRENAPkE/Oj0+P0A9Pz0+Q0NCQkRJSUlKSUtMTEpLTFBU
VlVUVlZSWVteXFpYU1RXWFlVWFlXV1VTVVJPUlZaVldTUVJRUVFOUE1KTE1LSElF
QUVEQkVCRUNERD8/Pjs8QDw6Ojo6Ozw5Nzk5PDc2NDQ4Ojg6OTk4Ojc4PEQ7Oj0/
PUNCRkNBSUtHSERJTEdKR1BLUVlVV1ZiV1BLU1JVVVZWU1RbWVBJQzo9NzY3NzYy
Mjc3ODg0MzU3OTk/Pjo8Oz1ERk9FRkVJSklXUkxWUVBRSlFPV1ZHTU9SXlVdVVdc
VlZMUk1QWVJRUFNZWF5eWU9PU1VWVFRSWFBPVllbWlZYWVdUVFFYXFhTUkxKQTo0
MjQ1OT5DVFhPV1paYFtgX15gX1FPUlRUWltbVlNPUVdWUlhXXVZVVldaVlNWVllZ
VFNPTVNRTVFPUlNUUVVUUlhVU1ZRS0lLRk1LSFFPTVFNTUpLT01LUlRMTVNVU1BU
V1tiWFVQSUNDQEVDSEhHVVJYWlBYXn6Ypqiil4qBfHp4cGttcHNtYFBDOz47Ojo3
OT07ODo7Oz88OjxAREA8Pj07OjxBQTw4PUFEQTxAPTtBRUVGR0U+QEI+ODUzMzc2
Njc4ODQxNDY3OTs8P0RKR0hSTlVfVVtRT09RU1VSUVJTU1JQS05OTVJXVVZUUVNY
VVRSTUxOSUtMSktKTEpJTEpKRkdLTE1NT01NSklJSktOTkpGREdGQUFERUREREI9
Pj4/Ozc5ODo5Njc6OTs5NzpBSlhja21vb3RxcHBucnp9eXl6fH+EhIWGjo2Njo+N
j4+MiYuLhH54cm5tb3BzfYaLjo6MjpKSkpORlJeWkpCHfnNrYVdWVVRMQj0/RE9V
UVJQUVFRVFtcXF1dXFlWVlZXV1FRTk9NS0VDQ0FBQUFAP0FER0dHR0dHSUhKSkxL
TEpJTlJOUFFUVlNWVltcYGBfZGhnaW5wcnR2dXh6eXt8f4GBgoKAg4GBgoODgoSE
iIiHio6Ni4+Sk46KjY6Qk5WVkpGUlJOSlpKSlJWTkpOYmJiYmZial5iZm5mZmpye
nZ+foKGip7Cyt7e5vLyznpKcn5aVorO5wcC/wLm2sa2rrK+zuLa4uL2/v768vMDA
wsG+wL68vra1tLK1tri8vbi6ubi2tre3tra1tbW4trGroY1tW1hUVFNNTk5KSktP
T0tLSkpMSktNTExLS0tLSkxKSUlMTUtLSk5JSE1OTk9MTE9RT0xNUFBRU1BPTU1P
UFBTUlFPUlFOUVNRUFFRUU9OUFFTU1NTUlNUVFJTUU5QUlJUVVRUU1ZST1BPUFFS
UVBOUVJPUFJSUFJRU1NRUFFSVFNSVFNUVFFRU1RXVlVXVFlYWFhZWFhVWFZUWFdX
XV1cWFdYWVdaWFdaVVVaWVlaWVdaWVlYVVdaWVlXWFlbWFdYWVpdW1xcXlpbX2Fj
YmBhYV9fX15cXl9aWFlVUFZWV1lYWVlXU1VvorzJ0tre4eTm5+jq6nl3d3l4d3h6
ent8fHh2dXN1d3NxbGFUSkdGSEM7Pj89QUhJRkZFQ0RFQ0JCQj09PTg8PUE7Oj4+
Qz0/QEFDQkVHR0pJSUxLTU1MTExLT1FSVFNTVVRVWFdXV1ZRUlNWVlVXWFlXWlta
VFZXWlxZV1VTVVBTUU1NTEtNS05MR0pMSEVER0ZISEVERD4+Ozs6Ozs6OTk6Ojc1
NTY5ODY2Njg2NzY4ODk3PDo4Pjw8PD9CRUFBPT5GRkVLTEZLTVFKSkxSW1daV11Z
SlJWVlNSV1pUU1dXVlZQQjo7OTU1NDMyNjc0NTZINzc3OTo8PT07QUJDUkpOS0hN
R1RRTlRQTlFIUFJVVEhSUVJgV1ZSWmFeYFJVTk5VUlJQV1lUVVZQSk5OUVZYVFBP
UFNUWV1XUlRZWFlXVFVcXlpWWFBCOTIyMzc2PUNNV01TWlpbW1paXl1VVFZXVVZZ
V1lcUk1OU1BVXVlaVlNTUVNYVVVbUk9VT05JTE9SUU9QUVZVUlNVWFlUS05LTFFU
V09SUFNSUVRNSkpNUk5OV1FNVFpSTlRcYVxYW1FKQ0JER0NFR0hTTFFUTlVWbYma
paOelImBfXx7dnRxcXBpWkY9Oj1COTQ5Ozs7QTk6Pzw7Ozs/QEJDPDo6PkBFPjtA
QkRFQjk6PUJGREZEQkFCRj04MzQ1ODk1NTM5NzQ0NTk6Oj49P0JFSFRRWFlSXFNS
VlZXVVRTU1ZTUFNNTU5PUFRUV1lRTk5SU09MTU5PUVBKS01MSkhIS0pJR0hDR0tL
TUtFSk1OS0tIR0VHRkhEQ0NGRENBPj89PT87PDs4Ojw4OTo4Njk9QUxZZG1vb3By
cnFzcnR2fH99eHh7gISHjJKJjpGRk5WSkpKOiomIgHx0cm5vcXV+hIeLjo+SlZiY
mJWUlZmSjIJ4cG1jVE5NTkxIQ0ZMVFhXVldUVldYXWBiX19gXFxbWlhXU1FPTk1L

View File

@ -0,0 +1,136 @@
TUxOT1JVUFNUVlVRT1VYWVdXUlJUT1FPU1VPT01PUE9WVlFSUFJRTkxKTU1PTEtJ
R0JDR0RDQEBBQD8/PDs/PD0+Pz44NzY1NjY5ODw5OT08Nzk5ODs8QUNBQj9BQUND
QklLSk5KSU9TXlhLT0xWUlFaVFdMTVdVW1VgWVdWXV9dWFtWUlFSTkVERTk1NTUz
MzUzNjU0ODg1ODY2Nzk6PTo6P0NETE1JR1RSTFBISkpKVVVLSUpUTU5STVZRVFpT
Vk5XXGBYUFhVWFJTV19kXVdVUFdVVlZUW1xbWlhZV1pcWE9TWlRWWVlXUE1MTlJD
PDo8Ozo+P0pOTVhWVFJWW15oYFxbXlpUVlpZXFhYVVdXUFlcYFhUVFdaW1RQXVxc
XltXUVBSTU1RUVRYVVNNSU1RUFFWVFFST05QUk9OSU5QTk1KS1BVSkxLTE5LT1RO
VlRZWlZYVE1FRkVHR0ZLSU9LTlFOXWaJo7CspZ2WlZOJfXFmYmFqdG9eS0E+OTk4
ODtBQTw9Ojg5PD5EQT8/P0BAPDc6OEE+Pzo+QENAPDtBQENDRkNDR0A6QEQ8ODU0
MTQ3NTg3Mzc2NDg0OTs/RUpTS05JT1xYWVlUXFZWVVtdWVlXUE5TUlJQT1BUVlZR
VFVYW1NRTkxMUlZUUEtMTk9PTE1MSERESUpLSkxJRklJSUtLRkRJSEVCRENERUZE
QkNBQ0JEQ0FAPjk6PDo3OTc3ODU2ODY2NTc+Rk9YYmdqaGhna3B3e3x+gYGBgYaH
iYuKi4uKioWCfXdwbmpnaWlsb3eCiIuMjYmJjo6SkJCTl5ORjIaBfnZnVEc/Ojo6
ODo7P0RJSkxPUlVWWVhWVlVSVFFRT05JRkVARD5BPkBCRERDQ0ZGRUdFSUpKSkpK
SklOS0xNTkxOT05MS0tMTk9NT1ZWU1dZWl1eXWJkZ2hqbm91dXV4fH5/gYB/gYOC
hYmGiIiHh4iGh4qLi4qMjY2Li4uLjZKTlpeWlpSPjo+SkZOQkpGRlZiXlpaZmZuZ
mZibl5mZmJiampual5aYnKCpr7KqmImGiJWosbzAvLu5u7i1tbGwsbKzt7a8vcC/
vL29vr6/v7q8vLq8vrq4ube1tLe3t7S0ta2ysrK1tKyginBfXVhTUlBOTVBMTU9M
S0tLSUpLSkhJSkdPT05KSUdNS0lJSE1LSkxKTk9MTUtNSk9OTUxPUU5NUE9OT0xM
Tk5QUVFQUU9QUVJSVFVSUlNTU1JRTlJTUFBSVFRSUlFTT09RUlBSUVNTUU9QUVNV
VVVVUVFSU1FVU1JSUFFSU1hUUVFPUVRQUVJRU1NUVVZYWFZWWlhYVFFVWFhXVlhW
WFhaWltbWF5bV1dYVlhbWFZYWVlaWVlYV1laWVpZV1taWVlaWlpaWVtcXV1cXF1d
YF9dYF5dXV1dYF5bXV1cWlxWV1dYV1ZWWFdYV1ZZXIO9ydPa3uHk5efo6el7enh5
ent8eHd1dnl2dnh6enl4eXdwZ1pMR0VFSkVEQz09Q0hKQ0A/P0I/PEJCQT4+PTpA
RURFQ0RHQ0RBPT5ARkhJSkxMTk1JS05QTklKTk5QUVNUU1FXU1ddWVVRUFFTU1JQ
UlBQT0tRVVVVU1JSUFJNSktPT0tJSUhHREVFQ0dEQkNAPj0+PTw7Ozs6OTw2Nzk4
ODg6PDs5OTg3Nzs4Ojw7Ozw9PURBQkQ/RktGS0tISUpRVU5RTUpTT1lTV1VOVlNc
WV1cWVddY1xdXllPT1JVT0pAODc1MzU5Njc6OTs3Njg2NTc7ODg4OTg+Q0dPUEpH
VVRMUUxRSkpUTklOSVNSTU1KV1RSWlFYVFRVWVdNUFJeVFRVYWFdXVZQUVVYV1VZ
VFdYWVhZXGVhVlRbW1pXUU1LTFBMTkhAOTg6OTk7Q1BSVVldWFpeXmFhY2VjXlNR
U1BXWFVVUVZYWFdWU1NTVVZaV09WWVlaWlNQTUtOUE1OUlhZVFFXUE1NUFBQTlFS
UFJWTU1OS0pRSkVJUFBNSkpNUEtPVFVXV1lXVldXU0hGRUdJSVBJSUhOVE9RWnWU
qauroZiVkYl8c2xmY2VrdWlSQTs6Ozg7OTw8Oz08PDw7Ozw7PTtAPj09Pj1BQUJA
OTo+QUQ9OD1FQUM+RUJCOzY9Q0E4ODU0NDY2NjQ0MzI1Njg4Oz1ESkpISkpTWlhY
W1ZZV1hTVldOUVNOTE5OUlFQVFlYU01XV1dWU09MSktOUlRTUU1PT0xQTklFR0ZL
TU1LS0dHR0dJSkpGRUNGSExHQ0RDREVBQD9APz5AOzs+QD88Pjw4NjY0Njc5Nzg7
QUpTXmRmaGdoaGxwdHp7fXmBh4eHhoyQj5CNjYuJhYJ8dnN1b2xtbGtze4SJjI6M
iImOj5KUlpWVk5GQi4B3a11RRj5APkFAQUFCSEpLTVBQU1hYWFZWV1NRUlBQTkxJ
RkdDQT5AP0NDQkNARERJR0lJRkhHSUtQUE1MS0tNTExNTE1NT1FSUFBVVVVXWF1f
XmNjZGdsbG5zdXZ1dnt9f4CDg4F/goOFhYaGh4uHhoWJi4mKi4mIiouNjIuMkZGR
lpSUj5GQkpKSkpWTkpaXl5OVlpmbmpiYmZmZmJqWlZeYl5iZmp+jqrO5s6aTgXeB
mK64vby7urq9ure0srSztba1t7m9vsDDwr69vb+9uru+wL69vbi3tbSztbq1tLe4
rrOztrW1saylknplXFZUVVNPTU9PTk5NTU1NSkhISkpJR0lKS0lKUEpKS0xPTVBL
TUxKS01KTExMTkpPTktQUE5PT09QTU5NUFBSUlNST1BPT05ST05PUVFTVlJSU1NS
UlRTUVJTUVBRUU5RTlFSU1NQTk5NUFVTUlBSUVBRVFRTU1NSVFJQUlVUVlNUVFFS
UFNVU1JUVVVWVVZXV1VWV1dWVVVYWVhZW1pYWVtdXF5aW1hZWFZZWVhYWlpYV1dY
WFZXW1tZWFlYWVhWWVlZXFxcW11cXltcXltdXlxdX19dXl5bXVtbWFlYV1VXV1ZU
VlVVVVdgfLvJ0dre4eTm5+jp6nl7e3x7eHp6dnh5dnd4dXd4dnZ5cmlgUkhCQEJH
QEM/PkFCRERBQERDQz4/QkU7PD1CPkBBQUFAQEFDR0I9PENCR0dISEdJTklMT01P
UlFNUFBRUlJZVVVWV1ZUU1hSVFZVUlJTUlBRUVNTVFVSUFFOUE5NTExPTUtIREhH
RENDQkJFQj5APkE/Pz87Oj08Oz04Nzc4NzxBODQ1Nzc4Ozo6Ojg2OTs7Ozs+QT9D
SUdISEZGRkpQS01LRElHTEpLVVRaWVhZXFtZVlhgX1xXV1BVblVUSkA5NzQ1NDc1
NTQzNDQ0NDg1Njc2NTg7PD8+PkpJTUZNT0dPS1JNSFBLRkxIS0hLSk1UVFlgVl5X
UVJUVUxRT1ZVUlFZXVpWVFJTVllZV1dUVFtaWltfZl1VWFtcVlZVT0tTUElIR0Q5
NzY3Njk/SVJWWmxlWlxdWWBpYV9kV1JUUVJcWlhTT1NSV1pTVFNTVlVXVlZVWFJU
WlNPS01VVVpaWVVYV1VWUU5QTk5PUFVRTE1LS0xIRU5KSEpOTk1JR01MSVBVWlxT
VFhcWFpZTkdDQEFFS0VISElTUU9WYniWpqiooJeOhn92a2NgYGZwbV5JOzs/QkI7
ODs9OkA+PDw6OT1APj4+SDw6Oz4/QkA7O0A9Pz5CPDs8QTxDQkJJPzpBPzo8Ozg2
NzQ3NjczMjQ2Nzg7PT9HS0RJR01SUldSUE9OT01VWFJWVE5LTlFTUlBSVldSVFhW
VFJWUVBNTEhLTFJUTExNS05OSUZITE1LS0pKT0pGREVGRkdIRklKSUlERURCQ0NC
Q0E+PDk9QD9BPzw6ODo4OTo9Ojg5PUdQW2VqamlrbWttcnd6fH19fYKDiI2Ojo2N
jo6LjIiIhX58eXVzcW9sb3d/hIyOkI+Lio6QkZOYlpSTjYuHgXJkWE1IRD89QEJF
RUZMT0xPUVNUVlhaW1lXVVNSUlJPTUtNS0dDQUJEQkJDRUZGR0hFR0dHQ0dHSEtI
SEtJS05LS0xSUVNQTlFUUlVZWFlcXWFlZ2hsbW9zcnV8fH9+fX+AgYGBg4SEg4KD
hYOCh4eHh4eJi4qKi4uOjI2KjpGSlZWUmZaSkpeWkI6TmJWYmpiXmJiampuXnJmY
lpaZmJqYmZmbnJ2jrLGwsbSwopSDfIeXrLu/vr28urq4s7OzsrK0trW3ubu8v8G/
v7++vr27ur27vLy7ubW2uby7t7e1ube1tbe2tLW0sa+mmIFmWldXUlBRT0xOS0xO
TVJPTUtKR0lKTEpKTUpJSUlLTUxJTE1PUExJS0tNS0xOTU5MS0xLS09PUVFTUE9R
UFNSU1FRVFJNT09OTlBQUlNSUVBRT1JUVFFPUVRUUVNRUE5QUVFSUFFPSk5RUE9P
UVNTVlFRTFBPUVJSUlJRT09SUlBQUE9RUlJTVVVTVFVWV1ZYWFZYV1hVVVRTV1ta
W11bWVxaXV1aWlpcWllZWllaXV5bV1dXWFpZWldXWVpZVlVXWVlbXFxaXF9cX11f
XFxcX15iYWBdXFhaW1pfXFtZV1RWVllXU1NXW2Z9usjT2d/h4+bn6OnpeXp7enl7
d3t7enl6eHp4eHl1dG9rZFtRSkdDQkBAQUY/PEVESUREREM9QUFEQUVBPT9BPT8/
Pz8+QT5BRENHQkNFRkhJS0xNTkxQTE1SU1NQUlNRUlVWVVVZWlZVU1VWU1ZWVFJQ
VlJPUFNXWFZVU1RUUFFPTkxISEdJTEpGREJCQUBAQENHQj07PTo8OzU5Nzc4ODg3
Nzg1ODk4ODc5Ozg6ODk3OTk4PD5FQj5AQEBFREU/QlFPSklIR0dHSkxUU1xZUVVZ
YFhPU2BaV1RYUU9UWFZKQDo3NzI0NTAyNjQ0Ozg4Njc2Nzk5ODw6Ozo+S0ZLRUdF
Q1RMWlVMUU9KT0pPTFVWSlVTVFtTWlNUVlJSTFNOUlRQSlRUWVdaWVVSUldZWlVT
U1dUU1pdXFZXW15VVVVOTldSTUdHRzo2NzU2OTk+TV1eYmJYX11aYGleX2lYTVJR
Vl5gXFhRUVNYXFJSWl1ZVlFWWlJSU1JcVVhTTlhYWFNTU1lYVVhSTU9RUVRTT05F
SEhJRk9NS01OTU9KS1FJTFFRUlNUV1FTV1xdX1lRSERBQkJHRkpJRVJRU1dVYnqW
pKekno+Jg3pybWhkZW1yZ1BEPDw+PTs3PDpEQ0E9Ozs7PDs/PEdCOjk9Oz1AQkA9
QEFEQj06Ojw7PT9ASUhAPEFCPDg4OTczNDM2NDQ1MzU2ODk6PD5FRk1JUE5WXlJU
UkxMTFVVT1BSUFRVVk5ISlNVVVRWWFRUVltYWE9LTUtKSkxJSUhLTU9NSUlMTkxI
TU9NR0NHSElLS0xISkhKRkNBQ0RCREJCQz49PDtAPjw6ODg5PDs5Ozg2OkBLWGNo
am1tbWtubXB1enp7e36Bg4aGiZKRjo2NjY2LiIiFhoKCd3Vua25vdH2DjI6NjIyO
kpGQkpOVko+NiYN4aV5XU01LSUI+PUNHTFFSU05RUlVUWVtcXFZUUlFUU1FPTkxK
R0ZCQUBAQUFEQz5CR0pIR0hESUhHRElKSklLS05MUFJVU1JRU1VaWFxdX19iY2lr
bW9ycnR3enp5e318fX9/gH6Cg4SFgIOFhoeGh4mMiouOjo6PjY+MjY2RlJKSlJuX
lZSUlZaQkpKWl5qTk5aYmpqbm5yampyam5mWl5uenZ+lqK2ytby9tqmcmJiRjJit
uL6/vru6uLKuq62vs7a2t7e6u73BwcHAwcG/vcC9vLm4u7e4t7i4ur29urq4tre6
uLa5trWzs62onohtXFVUVFJRT01NS0tKS05RS0tKS0xPTklJS0pJSUdLTEtJTEpO
S0tHSUpNT05QTk5LS0xQTlBPUFJRTVBRTk9OT05PUlJPUlBQTk9QUFFRT1FRVVNU
VFRTUlFWU1JQU1JRUFNVV1RPT1BRT1*SUVNUU1JOTlBPUFBQU1RSUVBSUVNSUVNR
UVNVVFRTVVRWVFJTVlhXWVdXU1NTWFtbWl5dXFlZWFhZWFxYVlpYWFlbWVpZWVZX
V1dYWVhYWFdXVVRZW1pZWlxdW1peXl1cXGBgX19gYV9fW1pZW1lcW1hWVFVXVVlW
U1NVaoS8ytPa3uLk5+jo6el4eXh1eXh9eHt7e3t4eHZ1eHh0cm5jWEtLTEY/PTs8
P0NGSklGREVBOz0+RD9BRENAPkE/Oj0+P0A9Pz0+Q0NCQkRJSUlKSUtMTEpLTFBU
VlVUVlZSWVteXFpYU1RXWFlVWFlXV1VTVVJPUlZaVldTUVJRUVFOUE1KTE1LSElF
QUVEQkVCRUNERD8/Pjs8QDw6Ojo6Ozw5Nzk5PDc2NDQ4Ojg6OTk4Ojc4PEQ7Oj0/
PUNCRkNBSUtHSERJTEdKR1BLUVlVV1ZiV1BLU1JVVVZWU1RbWVBJQzo9NzY3NzYy
Mjc3ODg0MzU3OTk/Pjo8Oz1ERk9FRkVJSklXUkxWUVBRSlFPV1ZHTU9SXlVdVVdc
VlZMUk1QWVJRUFNZWF5eWU9PU1VWVFRSWFBPVllbWlZYWVdUVFFYXFhTUkxKQTo0
MjQ1OT5DVFhPV1paYFtgX15gX1FPUlRUWltbVlNPUVdWUlhXXVZVVldaVlNWVllZ
VFNPTVNRTVFPUlNUUVVUUlhVU1ZRS0lLRk1LSFFPTVFNTUpLT01LUlRMTVNVU1BU
V1tiWFVQSUNDQEVDSEhHVVJYWlBYXn6Ypqiil4qBfHp4cGttcHNtYFBDOz47Ojo3
OT07ODo7Oz88OjxAREA8Pj07OjxBQTw4PUFEQTxAPTtBRUVGR0U+QEI+ODUzMzc2
Njc4ODQxNDY3OTs8P0RKR0hSTlVfVVtRT09RU1VSUVJTU1JQS05OTVJXVVZUUVNY
VVRSTUxOSUtMSktKTEpJTEpKRkdLTE1NT01NSklJSktOTkpGREdGQUFERUREREI9
Pj4/Ozc5ODo5Njc6OTs5NzpBSlhja21vb3RxcHBucnp9eXl6fH+EhIWGjo2Njo+N
j4+MiYuLhH54cm5tb3BzfYaLjo6MjpKSkpORlJeWkpCHfnNrYVdWVVRMQj0/RE9V
UVJQUVFRVFtcXF1dXFlWVlZXV1FRTk9NS0VDQ0FBQUFAP0FER0dHR0dHSUhKSkxL
TEpJTlJOUFFUVlNWVltcYGBfZGhnaW5wcnR2dXh6eXt8f4GBgoKAg4GBgoODgoSE
iIiHio6Ni4+Sk46KjY6Qk5WVkpGUlJOSlpKSlJWTkpOYmJiYmZial5iZm5mZmpye
nZ+foKGip7Cyt7e5vLyznpKcn5aVorO5wcC/wLm2sa2rrK+zuLa4uL2/v768vMDA
wsG+wL68vra1tLK1tri8vbi6ubi2tre3tra1tbW4trGroY1tW1hUVFNNTk5KSktP
T0tLSkpMSktNTExLS0tLSkxKSUlMTUtLSk5JSE1OTk9MTE9RT0xNUFBRU1BPTU1P
UFBTUlFPUlFOUVNRUFFRUU9OUFFTU1NTUlNUVFJTUU5QUlJUVVRUU1ZST1BPUFFS
UVBOUVJPUFJSUFJRU1NRUFFSVFNSVFNUVFFRU1RXVlVXVFlYWFhZWFhVWFZUWFdX
XV1cWFdYWVdaWFdaVVVaWVlaWVdaWVlYVVdaWVlXWFlbWFdYWVpdW1xcXlpbX2Fj
YmBhYV9fX15cXl9aWFlVUFZWV1lYWVlXU1V#orzJ0tre4eTm5+jq6nl3d3l4d3h6
ent8fHh2dXN1d3NxbGFUSkdGSEM7Pj89QUhJRkZFQ0RFQ0JCQj09PTg8PUE7Oj4+
Qz0/QEFDQkVHR0pJSUxLTU1MTExLT1FSVFNTVVRVWFdXV1ZRUlNWVlVXWFlXWlta
VFZXWlxZV1VTVVBTUU1NTEtNS05MR0pMSEVER0ZISEVERD4+Ozs6Ozs6OTk6Ojc1
NTY5ODY2Njg2NzY4ODk3PDo4Pjw8PD9CRUFBPT5GRkVLTEZLTVFKSkxSW1daV11Z
SlJWVlNSV1pUU1dXVlZQQjo7OTU1NDMyNjc0NTZINzc3OTo8PT07QUJDUkpOS0hN
R1RRTlRQTlFIUFJVVEhSUVJgV1ZSWmFeYFJVTk5VUlJQV1lUVVZQSk5OUVZYVFBP
UFNUWV1XUlRZWFlXVFVcXlpWWFBCOTIyMzc2PUNNV01TWlpbW1paXl1VVFZXVVZZ
V1lcUk1OU1BVXVlaVlNTUVNYVVVbUk9VT05JTE9SUU9QUVZVUlNVWFlUS05LTFFU
V09SUFNSUVRNSkpNUk5OV1FNVFpSTlRcYVxYW1FKQ0JER0NFR0hTTFFUTlVWbYma
paOelImBfXx7dnRxcXBpWkY9Oj1COTQ5Ozs7QTk6Pzw7Ozs/QEJDPDo6PkBFPjtA
QkRFQjk6PUJGREZEQkFCRj04MzQ1ODk1NTM5NzQ0NTk6Oj49P0JFSFRRWFlSXFNS
VlZXVVRTU1ZTUFNNTU5PUFRUV1lRTk5SU09MTU5PUVBKS01MSkhIS0pJR0hDR0tL
TUtFSk1OS0tIR0VHRkhEQ0NGRENBPj89PT87PDs4Ojw4OTo4Njk9QUxZZG1vb3By
cnFzcnR2fH99eHh7gISHjJKJjpGRk5WSkpKOiomIgHx0cm5vcXV+hIeLjo+SlZiY
mJWUlZmSjIJ4cG1jVE5NTkxIQ0ZMVFhXVldUVldYXWBiX19gXFxbWlhXU1FPTk1L