#include <iostream>
#include <vector> //for containers
#include <algorithm> //for remove_if
#include <utility> //for pair
#include <cassert>
namespace sisl { // signal slot
namespace detail {
//==============types for customization===================
template < typename TInvokable>
struct SlotContainer {
typedef std:: vector < TInvokable> type;
} ;
template < typename TResult>
struct ReturnValueAggregateContainerType {
typedef std:: vector < TResult> type;
} ;
/**
* @brief The LockingDisabled struct is a locking implementation
* which does nothing which is the default synchronization behaviour.
*/
struct LockingDisabled{
struct Mutex{ } ;
struct ScopedLock{ ScopedLock( Mutex const & ) { } } ;
} ;
struct ScopedLock{
typedef LockingDisabled:: ScopedLock type;
} ;
struct Mutex{
typedef LockingDisabled:: Mutex type;
} ;
/**
* @brief Instances of this struct represent the aggregated return values
*/
template < typename R>
struct ReturnValueAggregate {
typedef typename ReturnValueAggregateContainerType< R> :: type type;
operator type( ) const { return out; }
type out;
} ;
template <>
struct ReturnValueAggregate< void > { } ;
/**
* @brief This interface represents an abstract call.
*/
template < typename R = void , typename A1 = void , typename A2 = void , typename A3 = void , typename A4 = void , typename A5 = void >
struct Invokable;
template < typename R, typename A1, typename A2, typename A3, typename A4>
struct Invokable< R, A1, A2, A3, A4> {
virtual R operator( ) ( A1, A2, A3, A4) = 0 ;
virtual ~Invokable( ) { }
} ;
template < typename R, typename A1, typename A2, typename A3>
struct Invokable< R, A1, A2, A3> {
virtual R operator( ) ( A1, A2, A3) = 0 ;
virtual ~Invokable( ) { }
} ;
template < typename R, typename A1, typename A2>
struct Invokable< R, A1, A2> {
virtual R operator( ) ( A1, A2) = 0 ;
virtual ~Invokable( ) { }
} ;
template < typename R, typename A1>
struct Invokable< R, A1> {
virtual R operator( ) ( A1) = 0 ;
virtual ~Invokable( ) { }
} ;
template < typename R>
struct Invokable< R> {
virtual R operator( ) ( ) = 0 ;
virtual ~Invokable( ) { }
} ;
//==============struct MemberFunc===================
struct Const{ } ;
struct NonConst{ } ;
/**
* @brief This helper class defines the type of a member function specialized for const / non-const.
*/
template < typename TObj, typename Constness, typename R = void , typename A1 = void , typename A2 = void , typename A3 = void , typename A4 = void >
struct MemberFunc;
template < typename TObj, typename R, typename A1, typename A2, typename A3, typename A4>
struct MemberFunc< TObj, NonConst, R, A1, A2, A3, A4> {
typedef R ( TObj:: * type) ( A1, A2, A3, A4) ;
} ;
template < typename TObj, typename R, typename A1, typename A2, typename A3>
struct MemberFunc< TObj, NonConst, R, A1, A2, A3> {
typedef R ( TObj:: * type) ( A1, A2, A3) ;
} ;
template < typename TObj, typename R, typename A1, typename A2>
struct MemberFunc< TObj, NonConst, R, A1, A2> {
typedef R ( TObj:: * type) ( A1, A2) ;
} ;
template < typename TObj, typename R, typename A1>
struct MemberFunc< TObj, NonConst, R, A1> {
typedef R ( TObj:: * type) ( A1) ;
} ;
template < typename R, typename TObj>
struct MemberFunc< TObj, NonConst, R> {
typedef R ( TObj:: * type) ( ) ;
} ;
template < typename TObj, typename R, typename A1, typename A2, typename A3, typename A4>
struct MemberFunc< TObj, Const, R, A1, A2, A3, A4> {
typedef R ( TObj:: * type) ( A1, A2, A3, A4) const ;
} ;
template < typename TObj, typename R, typename A1, typename A2, typename A3>
struct MemberFunc< TObj, Const, R, A1, A2, A3> {
typedef R ( TObj:: * type) ( A1, A2, A3) const ;
} ;
template < typename TObj, typename R, typename A1, typename A2>
struct MemberFunc< TObj, Const, R, A1, A2> {
typedef R ( TObj:: * type) ( A1, A2) const ;
} ;
template < typename TObj, typename R, typename A1>
struct MemberFunc< TObj, Const, R, A1> {
typedef R ( TObj:: * type) ( A1) const ;
} ;
template < typename R, typename TObj>
struct MemberFunc< TObj, Const, R> {
typedef R ( TObj:: * type) ( ) const ;
} ;
struct Default{ } ;
struct NonDefault{ } ;
//==============struct CallableImpl===================
/**
* @brief The struct CallableImpl contains conrcrete
* implementations of the Invokable-inferface specializing void and non-void cases
*/
template < typename R>
struct InvokableImpl {
typedef R R_;
template < typename A1 = void , typename A2 = void , typename A3 = void , typename A4 = void , typename A5 = void , typename isDefault = Default>
struct GlobalFunction;
template < typename A1, typename A2, typename A3, typename A4>
struct GlobalFunction< A1, A2, A3, A4> : public Invokable< R_, A1, A2, A3, A4> {
typedef GlobalFunction< A1, A2, A3, A4> Classtype;
typedef Invokable< R_, A1, A2, A3, A4> Superclass;
typedef R_ ( * Member) ( A1, A2, A3, A4) ;
virtual R_ operator( ) ( A1 a1, A2 a2, A3 a3, A4 a4) { return m_member( a1, a2, a3, a4) ; }
GlobalFunction( Member member) : m_member( member) { }
bool isEqual( Classtype const & other) const { return m_member == other.m_member ; }
private :
Member m_member;
} ;
template < typename A1, typename A2, typename A3>
struct GlobalFunction< A1, A2, A3> : public Invokable< R_, A1, A2, A3> {
typedef GlobalFunction< A1, A2, A3> Classtype;
typedef Invokable< R_, A1, A2, A3> Superclass;
typedef R_ ( * Member) ( A1, A2, A3) ;
virtual R_ operator( ) ( A1 a1, A2 a2, A3 a3) { return m_member( a1, a2, a3) ; }
GlobalFunction( Member member) : m_member( member) { }
bool isEqual( Classtype const & other) const { return m_member == other.m_member ; }
private :
Member m_member;
} ;
template < typename A1, typename A2>
struct GlobalFunction< A1, A2> : public Invokable< R_, A1, A2> {
typedef GlobalFunction< A1, A2> Classtype;
typedef Invokable< R_, A1, A2> Superclass;
typedef R_ ( * Member) ( A1, A2) ;
virtual R_ operator( ) ( A1 a1, A2 a2) { return m_member( a1, a2) ; }
GlobalFunction( Member member) : m_member( member) { }
bool isEqual( Classtype const & other) const { return m_member == other.m_member ; }
private :
Member m_member;
} ;
template < typename A1>
struct GlobalFunction< A1> : public Invokable< R_, A1> {
typedef GlobalFunction< A1> Classtype;
typedef Invokable< R_, A1> Superclass;
typedef R_ ( * Member) ( A1) ;
virtual R_ operator( ) ( A1 a1) { return m_member( a1) ; }
GlobalFunction( Member member) : m_member( member) { }
bool isEqual( Classtype const & other) const { return m_member == other.m_member ; }
private :
Member m_member;
} ;
template < typename isDefault> // must have at least one template parameter to compile!
struct GlobalFunction< void , void , void , void , void , isDefault> : public Invokable< R_> { //must be non-default!
typedef GlobalFunction< void , void , void , void , void , isDefault> Classtype;
typedef Invokable< R_> Superclass;
typedef R_ ( * Member) ( ) ;
virtual R_ operator( ) ( ) { return m_member( ) ; }
GlobalFunction( Member member) : m_member( member) { }
bool isEqual( Classtype const & other) const { return m_member == other.m_member ; }
private :
Member m_member;
} ;
//////////////////////////////////////////////////////////
template < typename TObj, typename Constness, typename A1 = void , typename A2 = void , typename A3 = void , typename A4 = void , typename A5 = void >
struct MemberFunction;
template < typename TObj, typename Constness, typename A1, typename A2, typename A3, typename A4>
struct MemberFunction< TObj, Constness, A1, A2, A3, A4> : public Invokable< R_, A1, A2, A3, A4> {
typedef MemberFunction< TObj, Constness, A1, A2, A3, A4> Classtype;
typedef Invokable< R_, A1, A2, A3, A4> Superclass;
typedef typename MemberFunc< TObj, Constness, R_, A1, A2, A3, A4> :: type Member;
virtual R_ operator( ) ( A1 a1, A2 a2, A3 a3, A4 a4) { return ( m_obj.* m_member) ( a1, a2, a3, a4) ; }
MemberFunction( TObj& obj, Member member) : m_obj( obj) , m_member( member) { }
bool isEqual( Classtype const & other) const {
return ( & m_obj == & ( other.m_obj ) ) && ( m_member == other.m_member ) ;
}
private :
TObj& m_obj;
Member m_member;
} ;
template < typename TObj, typename Constness, typename A1, typename A2, typename A3>
struct MemberFunction< TObj, Constness, A1, A2, A3> : public Invokable< R_, A1, A2, A3> {
typedef MemberFunction< TObj, Constness, A1, A2, A3> Classtype;
typedef Invokable< R_, A1, A2, A3> Superclass;
typedef typename MemberFunc< TObj, Constness, R_, A1, A2, A3> :: type Member;
virtual R_ operator( ) ( A1 a1, A2 a2, A3 a3) { return ( m_obj.* m_member) ( a1, a2, a3) ; }
MemberFunction( TObj& obj, Member member) : m_obj( obj) , m_member( member) { }
bool isEqual( Classtype const & other) const {
return ( & m_obj == & ( other.m_obj ) ) && ( m_member == other.m_member ) ;
}
private :
TObj& m_obj;
Member m_member;
} ;
template < typename TObj, typename Constness, typename A1, typename A2>
struct MemberFunction< TObj, Constness, A1, A2> : public Invokable< R_, A1, A2> {
typedef MemberFunction< TObj, Constness, A1, A2> Classtype;
typedef Invokable< R_, A1, A2> Superclass;
typedef typename MemberFunc< TObj, Constness, R_, A1, A2> :: type Member;
virtual R_ operator( ) ( A1 a1, A2 a2) { return ( m_obj.* m_member) ( a1, a2) ; }
MemberFunction( TObj& obj, Member member) : m_obj( obj) , m_member( member) { }
bool isEqual( Classtype const & other) const {
return ( & m_obj == & ( other.m_obj ) ) && ( m_member == other.m_member ) ;
}
private :
TObj& m_obj;
Member m_member;
} ;
template < typename TObj, typename Constness, typename A1>
struct MemberFunction< TObj, Constness, A1> : public Invokable< R_, A1> {
typedef MemberFunction< TObj, Constness, A1> Classtype;
typedef Invokable< R_, A1> Superclass;
typedef typename MemberFunc< TObj, Constness, R_, A1> :: type Member;
virtual R_ operator( ) ( A1 a1) { return ( m_obj.* m_member) ( a1) ; }
MemberFunction( TObj& obj, Member member) : m_obj( obj) , m_member( member) { }
bool isEqual( Classtype const & other) const {
return ( & m_obj == & ( other.m_obj ) ) && ( m_member == other.m_member ) ;
}
private :
TObj& m_obj;
Member m_member;
} ;
template < typename TObj, typename Constness>
struct MemberFunction< TObj, Constness> : public Invokable< R_> {
typedef MemberFunction< TObj, Constness> Classtype;
typedef Invokable< R_> Superclass;
typedef typename MemberFunc< TObj, Constness, R_> :: type Member;
virtual R_ operator( ) ( ) { return ( m_obj.* m_member) ( ) ; }
MemberFunction( TObj& obj, Member member) : m_obj( obj) , m_member( member) { }
bool isEqual( Classtype const & other) const {
return ( & m_obj == & ( other.m_obj ) ) && ( m_member == other.m_member ) ;
}
private :
TObj& m_obj;
Member m_member;
} ;
template < typename A1 = void , typename A2 = void , typename A3 = void , typename A4 = void , typename A5 = void , typename isDefault = Default>
struct BoundFunction;
template < typename A1, typename A2, typename A3, typename A4>
struct BoundFunction< A1, A2, A3, A4> {
A1 a1;
A2 a2;
A3 a3;
A4 a4;
BoundFunction( A1 a1_, A2 a2_, A3 a3_, A4 a4_) : a1( a1_) ,a2( a2_) ,a3( a3_) ,a4( a4_) { }
virtual R_ operator( ) ( Invokable< R_,A1, A2, A3, A4> & invokable) { return invokable( a1,a2,a3,a4) ; }
} ;
template < typename A1, typename A2, typename A3>
struct BoundFunction< A1, A2, A3> {
A1 a1;
A2 a2;
A3 a3;
BoundFunction( A1 a1_, A2 a2_, A3 a3_) : a1( a1_) ,a2( a2_) ,a3( a3_) { }
virtual R_ operator( ) ( Invokable< R_,A1, A2, A3> & invokable) { return invokable( a1,a2,a3) ; }
} ;
template < typename A1, typename A2>
struct BoundFunction< A1, A2> {
A1 a1;
A2 a2;
BoundFunction( A1 a1_, A2 a2_) : a1( a1_) ,a2( a2_) { }
virtual R_ operator( ) ( Invokable< R_,A1, A2> & invokable) { return invokable( a1,a2) ; }
} ;
template < typename A1>
struct BoundFunction< A1> {
A1 a1;
BoundFunction( A1 a1_) : a1( a1_) { }
virtual R_ operator( ) ( Invokable< R_,A1> & invokable) { return invokable( a1) ; }
} ;
template < typename isDefault> // must have at least one template parameter to compile!
struct BoundFunction< void ,void ,void ,void ,void ,isDefault> {
BoundFunction( ) { }
virtual R_ operator( ) ( Invokable< R_> & invokable) { return invokable( ) ; }
} ;
} ;
template <>
struct InvokableImpl< void > {
typedef void R_;
template < typename A1 = void , typename A2 = void , typename A3 = void , typename A4 = void , typename A5 = void , typename isDefault = Default>
struct GlobalFunction;
template < typename A1, typename A2, typename A3, typename A4>
struct GlobalFunction< A1, A2, A3, A4> : public Invokable< R_, A1, A2, A3, A4> {
typedef GlobalFunction< A1, A2, A3, A4> Classtype;
typedef Invokable< R_, A1, A2, A3, A4> Superclass;
typedef R_ ( * Member) ( A1, A2, A3, A4) ;
virtual R_ operator( ) ( A1 a1, A2 a2, A3 a3, A4 a4) { m_member( a1, a2, a3, a4) ; }
bool isEqual( Classtype const & other) const { return m_member == other.m_member ; }
GlobalFunction( Member member) : m_member( member) { }
private :
Member m_member;
} ;
template < typename A1, typename A2, typename A3>
struct GlobalFunction< A1, A2, A3> : public Invokable< R_, A1, A2, A3> {
typedef GlobalFunction< A1, A2, A3> Classtype;
typedef Invokable< R_, A1, A2, A3> Superclass;
typedef R_ ( * Member) ( A1, A2, A3) ;
virtual R_ operator( ) ( A1 a1, A2 a2, A3 a3) { m_member( a1, a2, a3) ; }
GlobalFunction( Member member) : m_member( member) { }
bool isEqual( Classtype const & other) const { return m_member == other.m_member ; }
private :
Member m_member;
} ;
template < typename A1, typename A2>
struct GlobalFunction< A1, A2> : public Invokable< R_, A1, A2> {
typedef GlobalFunction< A1, A2> Classtype;
typedef Invokable< R_, A1, A2> Superclass;
typedef R_ ( * Member) ( A1, A2) ;
virtual R_ operator( ) ( A1 a1, A2 a2) { m_member( a1, a2) ; }
GlobalFunction( Member member) : m_member( member) { }
bool isEqual( Classtype const & other) const { return m_member == other.m_member ; }
private :
Member m_member;
} ;
template < typename A1>
struct GlobalFunction< A1> : public Invokable< R_, A1> {
typedef GlobalFunction< A1> Classtype;
typedef Invokable< R_, A1> Superclass;
typedef R_ ( * Member) ( A1) ;
virtual R_ operator( ) ( A1 a1) { m_member( a1) ; }
GlobalFunction( Member member) : m_member( member) { }
bool isEqual( Classtype const & other) const { return m_member == other.m_member ; }
private :
Member m_member;
} ;
template < typename isDefault> // must have at least one template parameter to compile!
struct GlobalFunction< void , void , void , void , void , isDefault> : public Invokable< R_> { //must be nonDefault
typedef GlobalFunction< void , void , void , void , void , isDefault> Classtype;
typedef Invokable< R_> Superclass;
typedef R_ ( * Member) ( ) ;
virtual R_ operator( ) ( ) { m_member( ) ; }
GlobalFunction( Member member) : m_member( member) { }
bool isEqual( Classtype const & other) const { return m_member == other.m_member ; }
private :
Member m_member;
} ;
//////////////////////////////////////////////////////////
template < typename TObj, typename Constness, typename A1 = void , typename A2 = void , typename A3 = void , typename A4 = void , typename A5 = void >
struct MemberFunction;
template < typename TObj, typename Constness, typename A1, typename A2, typename A3, typename A4>
struct MemberFunction< TObj, Constness, A1, A2, A3, A4> : public Invokable< R_, A1, A2, A3, A4> {
typedef MemberFunction< TObj, Constness, A1, A2, A3, A4> Classtype;
typedef Invokable< R_, A1, A2, A3, A4> Superclass;
typedef typename MemberFunc< TObj, Constness, R_, A1, A2, A3, A4> :: type Member;
virtual R_ operator( ) ( A1 a1, A2 a2, A3 a3, A4 a4) { ( m_obj.* m_member) ( a1, a2, a3, a4) ; }
MemberFunction( TObj& obj, Member member) : m_obj( obj) , m_member( member) { }
bool isEqual( Classtype const & other) const {
return ( & m_obj == & ( other.m_obj ) ) && ( m_member == other.m_member ) ;
}
private :
TObj& m_obj;
Member m_member;
} ;
template < typename TObj, typename Constness, typename A1, typename A2, typename A3>
struct MemberFunction< TObj, Constness, A1, A2, A3> : public Invokable< R_, A1, A2, A3> {
typedef MemberFunction< TObj, Constness, A1, A2, A3> Classtype;
typedef Invokable< R_, A1, A2, A3> Superclass;
typedef typename MemberFunc< TObj, Constness, R_, A1, A2, A3> :: type Member;
virtual R_ operator( ) ( A1 a1, A2 a2, A3 a3) { ( m_obj.* m_member) ( a1, a2, a3) ; }
MemberFunction( TObj& obj, Member member) : m_obj( obj) , m_member( member) { }
bool isEqual( Classtype const & other) const {
return ( & m_obj == & ( other.m_obj ) ) && ( m_member == other.m_member ) ;
}
private :
TObj& m_obj;
Member m_member;
} ;
template < typename TObj, typename Constness, typename A1, typename A2>
struct MemberFunction< TObj, Constness, A1, A2> : public Invokable< R_, A1, A2> {
typedef MemberFunction< TObj, Constness, A1, A2> Classtype;
typedef Invokable< R_, A1, A2> Superclass;
typedef typename MemberFunc< TObj, Constness, R_, A1, A2> :: type Member;
virtual R_ operator( ) ( A1 a1, A2 a2) { ( m_obj.* m_member) ( a1, a2) ; }
MemberFunction( TObj& obj, Member member) : m_obj( obj) , m_member( member) { }
bool isEqual( Classtype const & other) const {
return ( & m_obj == & ( other.m_obj ) ) && ( m_member == other.m_member ) ;
}
private :
TObj& m_obj;
Member m_member;
} ;
template < typename TObj, typename Constness, typename A1>
struct MemberFunction< TObj, Constness, A1> : public Invokable< R_, A1> {
typedef MemberFunction< TObj, Constness, A1> Classtype;
typedef Invokable< R_, A1> Superclass;
typedef typename MemberFunc< TObj, Constness, R_, A1> :: type Member;
virtual R_ operator( ) ( A1 a1) { ( m_obj.* m_member) ( a1) ; }
MemberFunction( TObj& obj, Member member) : m_obj( obj) , m_member( member) { }
bool isEqual( Classtype const & other) const {
return ( & m_obj == & ( other.m_obj ) ) && ( m_member == other.m_member ) ;
}
private :
TObj& m_obj;
Member m_member;
} ;
template < typename TObj, typename Constness>
struct MemberFunction< TObj, Constness> : public Invokable< R_> {
typedef MemberFunction< TObj, Constness> Classtype;
typedef Invokable< R_> Superclass;
typedef typename MemberFunc< TObj, Constness, R_> :: type Member;
virtual R_ operator( ) ( ) { ( m_obj.* m_member) ( ) ; }
MemberFunction( TObj& obj, Member member) : m_obj( obj) , m_member( member) { }
bool isEqual( Classtype const & other) const {
return ( & m_obj == & ( other.m_obj ) ) && ( m_member == other.m_member ) ;
}
private :
TObj& m_obj;
Member m_member;
} ;
template < typename A1 = void , typename A2 = void , typename A3 = void , typename A4 = void , typename A5 = void , typename isDefault = Default>
struct BoundFunction;
template < typename A1, typename A2, typename A3, typename A4>
struct BoundFunction< A1, A2, A3, A4> {
A1 a1;
A2 a2;
A3 a3;
A4 a4;
BoundFunction( A1 a1_, A2 a2_, A3 a3_, A4 a4_) : a1( a1_) ,a2( a2_) ,a3( a3_) ,a4( a4_) { }
virtual R_ operator( ) ( Invokable< R_,A1, A2, A3, A4> & invokable) { invokable( a1,a2,a3,a4) ; }
} ;
template < typename A1, typename A2, typename A3>
struct BoundFunction< A1, A2, A3> {
A1 a1;
A2 a2;
A3 a3;
BoundFunction( A1 a1_, A2 a2_, A3 a3_) : a1( a1_) ,a2( a2_) ,a3( a3_) { }
virtual R_ operator( ) ( Invokable< R_,A1, A2, A3> & invokable) { invokable( a1,a2,a3) ; }
} ;
template < typename A1, typename A2>
struct BoundFunction< A1, A2> {
A1 a1;
A2 a2;
BoundFunction( A1 a1_, A2 a2_) : a1( a1_) ,a2( a2_) { }
virtual R_ operator( ) ( Invokable< R_,A1, A2> & invokable) { invokable( a1,a2) ; }
} ;
template < typename A1>
struct BoundFunction< A1> {
A1 a1;
BoundFunction( A1 a1_) : a1( a1_) { }
virtual R_ operator( ) ( Invokable< R_,A1> & invokable) { invokable( a1) ; }
} ;
template < typename isDefault> // must have at least one template parameter to compile!
struct BoundFunction< void ,void ,void ,void ,void ,isDefault> {
BoundFunction( ) { }
virtual R_ operator( ) ( Invokable< R_> & invokable) { invokable( ) ; }
} ;
} ;
struct ScopedInversion{
bool & target;
const bool origValue;
ScopedInversion( bool & target_) : target( target_) ,origValue( target_) { target = ! target; }
~ScopedInversion( ) { target = origValue; }
} ;
typedef bool DisconnectionPending;
inline DisconnectionPending disconnectPending( ) { return true ; }
inline DisconnectionPending connected( ) { return disconnectPending( ) == false ; }
template < typename TInvokablePtr>
struct IsPendingDisconnect {
typedef std:: pair < TInvokablePtr,bool > Slot;
bool operator( ) ( Slot const & other) const {
return other.second == disconnectPending( ) ;
}
} ;
/**
* @brief Comparing of 2 invokable instances
*/
template < typename TInvokable>
struct IsCaller {
typedef std:: pair < typename TInvokable:: Superclass * ,bool > Slot;
IsCaller( TInvokable const & c) : invokable( c) { }
TInvokable const & invokable;
bool operator( ) ( Slot const & other) const {
TInvokable const * t = dynamic_cast < TInvokable const * > ( other.first ) ;
return t! = NULL ? invokable.isEqual ( * t) : false ;
}
} ;
/**
* Removing a slot from the list of slots
*/
template < typename Slots>
void disconnectNow( Slots& slots) {
const IsPendingDisconnect< typename Slots:: value_type :: first_type > pred;
typedef typename Slots:: const_iterator It;
for ( It it = slots.begin ( ) , end = slots.end ( ) ; it! = end; ++ it)
if ( pred( * it) )
delete it- > first;
slots.erase ( std:: remove_if ( slots.begin ( ) ,slots.end ( ) , pred) , slots.end ( ) ) ;
}
template < typename Slots, typename TCaller>
void disconnectDelayed( Slots& slots, TCaller const & caller) {
const IsCaller< TCaller> pred( caller) ;
typedef typename Slots:: iterator It;
for ( It it = slots.begin ( ) , end = slots.end ( ) ; it! = end; ++ it)
if ( pred( * it) )
it- > second = disconnectPending( ) ;
}
template < typename Slots, typename TCaller>
void disconnect( Slots& slots, bool isCurrentlyEmitting, TCaller const & caller) {
disconnectDelayed( slots,caller) ;
if ( ! isCurrentlyEmitting)
disconnectNow( slots) ;
}
/**
* Removing a slot from the list of slots
*/
template < typename Slots>
void disconnectAll( Slots& slots) {
typedef typename Slots:: const_iterator SlotsCIt;
for ( SlotsCIt it = slots.begin ( ) , end = slots.end ( ) ; it ! = end; ++ it)
delete * it;
slots.clear ( ) ;
}
template < typename Slots>
void disconnectAllNow( Slots& slots) {
typedef typename Slots:: const_iterator SlotsCIt;
for ( SlotsCIt it = slots.begin ( ) , end = slots.end ( ) ; it ! = end; ++ it)
delete it- > first;
slots.clear ( ) ;
}
template < typename Slots>
void disconnectAllDelayed( Slots& slots) {
typedef typename Slots:: iterator SlotsCIt;
for ( SlotsCIt it = slots.begin ( ) , end = slots.end ( ) ; it ! = end; ++ it)
it- > second = disconnectPending( ) ;
}
template < typename Slots>
void disconnectAll( Slots& slots, bool isCurrentlyEmitting) {
if ( isCurrentlyEmitting)
disconnectAllDelayed( slots) ;
else
disconnectAllNow( slots) ;
}
template < typename OutType_, typename CallResult>
void aggregateReturnValue( OutType_& c, CallResult const & r) {
c.out .push_back ( r) ;
}
template < typename R>
struct ReturnValueAggregator {
typedef R R_;
template < typename Slots, typename Args>
static void invokeAndAggregate( ReturnValueAggregate< R_> & r, Slots& slots, Args& args) {
typedef typename Slots:: const_iterator SlotsCIt;
for ( SlotsCIt it = slots.begin ( ) , end = slots.end ( ) ; it ! = end; ++ it) {
aggregateReturnValue( r,args( * ( it- > first) ) ) ;
}
}
} ;
template <>
struct ReturnValueAggregator< void > {
typedef void R_;
template < typename Slots, typename Args>
static void invokeAndAggregate( ReturnValueAggregate< R_> & , Slots& slots, Args& args) {
typedef typename Slots:: const_iterator SlotsCIt;
for ( SlotsCIt it = slots.begin ( ) , end = slots.end ( ) ; it ! = end; ++ it) {
args( * ( it- > first) ) ;
}
}
} ;
template < typename Slots, typename Invokable>
void connect( Slots& slots, Invokable invokable) {
slots.push_back ( invokable) ;
}
template < typename Slots>
void connectPending( Slots& slots, Slots& pendingConnects) {
typedef typename Slots:: const_iterator SlotsCIt;
for ( SlotsCIt it = pendingConnects.begin ( ) , end = pendingConnects.end ( ) ; it ! = end; ++ it)
connect( slots,* it) ;
pendingConnects.clear ( ) ;
}
template < typename Slots>
void disconnectPending( Slots& slots) {
disconnectNow( slots) ;
}
} //namespace detail
/**
* @brief Main class realizing signal slot behaviour.
*/
template < typename TFunc>
struct Signal;
template < typename R, typename A1, typename A2, typename A3,typename A4>
struct Signal< R( A1, A2, A3, A4) > {
void connect( R ( * member) ( A1, A2, A3, A4) ) {
ScopedLock_ lock( slotsMutex) ;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new GCaller( member) ,detail:: connected ( ) ) ) ;
}
template < typename TObj>
void connect( TObj& obj, R ( TObj:: * member) ( A1, A2, A3, A4) ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< TObj,detail:: NonConst > :: type MCaller_;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new MCaller_( obj, member) ,detail:: connected ( ) ) ) ;
}
template < typename TObj>
void connect( TObj const & obj, R ( TObj:: * member) ( A1, A2, A3, A4) const ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< const TObj,detail:: Const > :: type MCaller_;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new MCaller_( obj, member) ,detail:: connected ( ) ) ) ;
}
detail:: ReturnValueAggregate < R> emit( A1 a1, A2 a2, A3 a3, A4 a4) {
ScopedLock_ lock( slotsMutex) ;
Args args( a1,a2,a3,a4) ;
detail:: ReturnValueAggregate < R> r;
if ( isCurrentlyEmitting) return r;
detail:: ScopedInversion inverter( isCurrentlyEmitting) ;
detail:: ReturnValueAggregator < R> :: invokeAndAggregate ( r, slots, args) ;
detail:: disconnectPending ( slots) ;
detail:: connectPending ( slots, pendingConnects) ;
return r;
}
void disconnect( R ( * member) ( A1, A2, A3, A4) ) {
ScopedLock_ lock( slotsMutex) ;
detail:: disconnect ( slots, isCurrentlyEmitting, GCaller( member) ) ;
}
template < typename TObj>
void disconnect( TObj& obj, R ( TObj:: * member) ( A1, A2, A3, A4) ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< TObj,detail:: NonConst > :: type MCaller_;
detail:: disconnect ( slots, isCurrentlyEmitting, MCaller_( obj,member) ) ;
}
template < typename TObj>
void disconnect( TObj const & obj, R ( TObj:: * member) ( A1, A2, A3, A4) const ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< const TObj,detail:: Const > :: type MCaller_;
detail:: disconnect ( slots, isCurrentlyEmitting, MCaller_( obj,member) ) ;
}
void disconnectAll( ) {
ScopedLock_ lock( slotsMutex) ;
detail:: disconnectAll ( slots, isCurrentlyEmitting) ;
}
~Signal( ) { assert ( isCurrentlyEmitting== false ) ; disconnectAll( ) ; } //upon returning from dtor object is invalid so a pending emit()-call would be invalid too!
private :
typedef typename detail:: InvokableImpl < R> :: template BoundFunction< A1, A2, A3, A4> Args;
typedef typename detail:: InvokableImpl < R> :: template GlobalFunction< A1, A2, A3, A4> GCaller;
template < typename TObj, typename Constness>
struct MCaller{ typedef typename detail:: InvokableImpl < R> :: template MemberFunction< TObj, Constness, A1, A2, A3, A4> type; } ;
typedef std:: pair < detail:: Invokable < R, A1, A2, A3, A4> * ,detail:: DisconnectionPending > Slot;
typedef typename detail:: SlotContainer < Slot> :: type Slots;
typedef detail:: Mutex :: type Mutex_;
typedef detail:: ScopedLock :: type ScopedLock_;
bool isCurrentlyEmitting = false ;
Slots pendingConnects;
Slots slots;
Mutex_ slotsMutex;
} ;
template < typename R, typename A1, typename A2, typename A3>
struct Signal< R( A1, A2, A3) > {
void connect( R ( * member) ( A1, A2, A3) ) {
ScopedLock_ lock( slotsMutex) ;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new GCaller( member) ,detail:: connected ( ) ) ) ;
}
template < typename TObj>
void connect( TObj& obj, R ( TObj:: * member) ( A1, A2, A3) ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< TObj,detail:: NonConst > :: type MCaller_;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new MCaller_( obj, member) ,detail:: connected ( ) ) ) ;
}
template < typename TObj>
void connect( TObj const & obj, R ( TObj:: * member) ( A1, A2, A3) const ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< const TObj,detail:: Const > :: type MCaller_;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new MCaller_( obj, member) ,detail:: connected ( ) ) ) ;
}
detail:: ReturnValueAggregate < R> emit( A1 a1, A2 a2, A3 a3) {
ScopedLock_ lock( slotsMutex) ;
Args args( a1,a2,a3) ;
detail:: ReturnValueAggregate < R> r;
if ( isCurrentlyEmitting) return r;
detail:: ScopedInversion inverter( isCurrentlyEmitting) ;
detail:: ReturnValueAggregator < R> :: invokeAndAggregate ( r, slots, args) ;
detail:: disconnectPending ( slots) ;
detail:: connectPending ( slots, pendingConnects) ;
return r;
}
void disconnect( R ( * member) ( A1, A2, A3) ) {
ScopedLock_ lock( slotsMutex) ;
detail:: disconnect ( slots, isCurrentlyEmitting, GCaller( member) ) ;
}
template < typename TObj>
void disconnect( TObj& obj, R ( TObj:: * member) ( A1, A2, A3) ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< TObj,detail:: NonConst > :: type MCaller_;
detail:: disconnect ( slots, isCurrentlyEmitting, MCaller_( obj,member) ) ;
}
template < typename TObj>
void disconnect( TObj const & obj, R ( TObj:: * member) ( A1, A2, A3) const ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< const TObj,detail:: Const > :: type MCaller_;
detail:: disconnect ( slots, isCurrentlyEmitting, MCaller_( obj,member) ) ;
}
void disconnectAll( ) {
ScopedLock_ lock( slotsMutex) ;
detail:: disconnectAll ( slots, isCurrentlyEmitting) ;
}
~Signal( ) { assert ( isCurrentlyEmitting== false ) ; disconnectAll( ) ; } //upon returning from dtor object is invalid so a pending emit()-call would be invalid too!
private :
typedef typename detail:: InvokableImpl < R> :: template BoundFunction< A1, A2, A3> Args;
typedef typename detail:: InvokableImpl < R> :: template GlobalFunction< A1, A2, A3> GCaller;
template < typename TObj, typename Constness>
struct MCaller{ typedef typename detail:: InvokableImpl < R> :: template MemberFunction< TObj, Constness, A1, A2, A3> type; } ;
typedef std:: pair < detail:: Invokable < R, A1, A2, A3> * ,detail:: DisconnectionPending > Slot;
typedef typename detail:: SlotContainer < Slot> :: type Slots;
typedef detail:: Mutex :: type Mutex_;
typedef detail:: ScopedLock :: type ScopedLock_;
bool isCurrentlyEmitting = false ;
Slots pendingConnects;
Slots slots;
Mutex_ slotsMutex;
} ;
template < typename R, typename A1, typename A2>
struct Signal< R( A1, A2) > {
void connect( R ( * member) ( A1, A2) ) {
ScopedLock_ lock( slotsMutex) ;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new GCaller( member) ,detail:: connected ( ) ) ) ;
}
template < typename TObj>
void connect( TObj& obj, R ( TObj:: * member) ( A1, A2) ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< TObj,detail:: NonConst > :: type MCaller_;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new MCaller_( obj, member) ,detail:: connected ( ) ) ) ;
}
template < typename TObj>
void connect( TObj const & obj, R ( TObj:: * member) ( A1, A2) const ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< const TObj,detail:: Const > :: type MCaller_;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new MCaller_( obj, member) ,detail:: connected ( ) ) ) ;
}
detail:: ReturnValueAggregate < R> emit( A1 a1, A2 a2) {
ScopedLock_ lock( slotsMutex) ;
Args args( a1,a2) ;
detail:: ReturnValueAggregate < R> r;
if ( isCurrentlyEmitting) return r;
detail:: ScopedInversion inverter( isCurrentlyEmitting) ;
detail:: ReturnValueAggregator < R> :: invokeAndAggregate ( r, slots, args) ;
detail:: disconnectPending ( slots) ;
detail:: connectPending ( slots, pendingConnects) ;
return r;
}
void disconnect( R ( * member) ( A1, A2) ) {
ScopedLock_ lock( slotsMutex) ;
detail:: disconnect ( slots, isCurrentlyEmitting, GCaller( member) ) ;
}
template < typename TObj>
void disconnect( TObj& obj, R ( TObj:: * member) ( A1, A2) ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< TObj,detail:: NonConst > :: type MCaller_;
detail:: disconnect ( slots, isCurrentlyEmitting, MCaller_( obj,member) ) ;
}
template < typename TObj>
void disconnect( TObj const & obj, R ( TObj:: * member) ( A1, A2) const ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< const TObj,detail:: Const > :: type MCaller_;
detail:: disconnect ( slots, isCurrentlyEmitting, MCaller_( obj,member) ) ;
}
void disconnectAll( ) {
ScopedLock_ lock( slotsMutex) ;
detail:: disconnectAll ( slots, isCurrentlyEmitting) ;
}
~Signal( ) { assert ( isCurrentlyEmitting== false ) ; disconnectAll( ) ; } //upon returning from dtor object is invalid so a pending emit()-call would be invalid too!
private :
typedef typename detail:: InvokableImpl < R> :: template BoundFunction< A1, A2> Args;
typedef typename detail:: InvokableImpl < R> :: template GlobalFunction< A1, A2> GCaller;
template < typename TObj, typename Constness>
struct MCaller{ typedef typename detail:: InvokableImpl < R> :: template MemberFunction< TObj, Constness, A1, A2> type; } ;
typedef std:: pair < detail:: Invokable < R, A1, A2> * ,detail:: DisconnectionPending > Slot;
typedef typename detail:: SlotContainer < Slot> :: type Slots;
typedef detail:: Mutex :: type Mutex_;
typedef detail:: ScopedLock :: type ScopedLock_;
bool isCurrentlyEmitting = false ;
Slots pendingConnects;
Slots slots;
Mutex_ slotsMutex;
} ;
template < typename R, typename A1>
struct Signal< R( A1) > {
void connect( R ( * member) ( A1) ) {
ScopedLock_ lock( slotsMutex) ;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new GCaller( member) ,detail:: connected ( ) ) ) ;
}
template < typename TObj>
void connect( TObj& obj, R ( TObj:: * member) ( A1) ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< TObj,detail:: NonConst > :: type MCaller_;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new MCaller_( obj, member) ,detail:: connected ( ) ) ) ;
}
template < typename TObj>
void connect( TObj const & obj, R ( TObj:: * member) ( A1) const ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< const TObj,detail:: Const > :: type MCaller_;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new MCaller_( obj, member) ,detail:: connected ( ) ) ) ;
}
detail:: ReturnValueAggregate < R> emit( A1 a1) {
ScopedLock_ lock( slotsMutex) ;
Args args( a1) ;
detail:: ReturnValueAggregate < R> r;
if ( isCurrentlyEmitting) return r;
detail:: ScopedInversion inverter( isCurrentlyEmitting) ;
detail:: ReturnValueAggregator < R> :: invokeAndAggregate ( r, slots, args) ;
detail:: disconnectPending ( slots) ;
detail:: connectPending ( slots, pendingConnects) ;
return r;
}
void disconnect( R ( * member) ( A1) ) {
ScopedLock_ lock( slotsMutex) ;
detail:: disconnect ( slots, isCurrentlyEmitting, GCaller( member) ) ;
}
template < typename TObj>
void disconnect( TObj& obj, R ( TObj:: * member) ( A1) ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< TObj,detail:: NonConst > :: type MCaller_;
detail:: disconnect ( slots, isCurrentlyEmitting, MCaller_( obj,member) ) ;
}
template < typename TObj>
void disconnect( TObj const & obj, R ( TObj:: * member) ( A1) const ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< const TObj,detail:: Const > :: type MCaller_;
detail:: disconnect ( slots, isCurrentlyEmitting, MCaller_( obj,member) ) ;
}
void disconnectAll( ) {
ScopedLock_ lock( slotsMutex) ;
detail:: disconnectAll ( slots, isCurrentlyEmitting) ;
}
~Signal( ) { assert ( isCurrentlyEmitting== false ) ; disconnectAll( ) ; } //upon returning from dtor object is invalid so a pending emit()-call would be invalid too!
private :
typedef typename detail:: InvokableImpl < R> :: template BoundFunction< A1> Args;
typedef typename detail:: InvokableImpl < R> :: template GlobalFunction< A1> GCaller;
template < typename TObj, typename Constness>
struct MCaller{ typedef typename detail:: InvokableImpl < R> :: template MemberFunction< TObj, Constness, A1> type; } ;
typedef std:: pair < detail:: Invokable < R, A1> * ,detail:: DisconnectionPending > Slot;
typedef typename detail:: SlotContainer < Slot> :: type Slots;
typedef detail:: Mutex :: type Mutex_;
typedef detail:: ScopedLock :: type ScopedLock_;
bool isCurrentlyEmitting = false ;
Slots pendingConnects;
Slots slots;
Mutex_ slotsMutex;
} ;
template < typename R>
struct Signal< R( ) > {
void connect( R ( * member) ( ) ) {
ScopedLock_ lock( slotsMutex) ;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new GCaller( member) ,detail:: connected ( ) ) ) ;
}
template < typename TObj>
void connect( TObj& obj, R ( TObj:: * member) ( ) ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< TObj,detail:: NonConst > :: type MCaller_;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new MCaller_( obj, member) ,detail:: connected ( ) ) ) ;
}
template < typename TObj>
void connect( TObj const & obj, R ( TObj:: * member) ( ) const ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< const TObj,detail:: Const > :: type MCaller_;
detail:: connect ( isCurrentlyEmitting ? pendingConnects : slots, Slot( new MCaller_( obj, member) ,detail:: connected ( ) ) ) ;
}
detail:: ReturnValueAggregate < R> emit( ) {
ScopedLock_ lock( slotsMutex) ;
Args args;
detail:: ReturnValueAggregate < R> r;
if ( isCurrentlyEmitting) return r;
detail:: ScopedInversion inverter( isCurrentlyEmitting) ;
detail:: ReturnValueAggregator < R> :: invokeAndAggregate ( r, slots, args) ;
detail:: disconnectPending ( slots) ;
detail:: connectPending ( slots, pendingConnects) ;
return r;
}
void disconnect( R ( * member) ( ) ) {
ScopedLock_ lock( slotsMutex) ;
detail:: disconnect ( slots, isCurrentlyEmitting, GCaller( member) ) ;
}
template < typename TObj>
void disconnect( TObj& obj, R ( TObj:: * member) ( ) ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< TObj,detail:: NonConst > :: type MCaller_;
detail:: disconnect ( slots, isCurrentlyEmitting, MCaller_( obj,member) ) ;
}
template < typename TObj>
void disconnect( TObj const & obj, R ( TObj:: * member) ( ) const ) {
ScopedLock_ lock( slotsMutex) ;
typedef typename MCaller< const TObj,detail:: Const > :: type MCaller_;
detail:: disconnect ( slots, isCurrentlyEmitting, MCaller_( obj,member) ) ;
}
void disconnectAll( ) {
ScopedLock_ lock( slotsMutex) ;
detail:: disconnectAll ( slots, isCurrentlyEmitting) ;
}
~Signal( ) { assert ( isCurrentlyEmitting== false ) ; disconnectAll( ) ; } //upon returning from dtor object is invalid so a pending emit()-call would be invalid too!
private :
typedef typename detail:: InvokableImpl < R> :: template BoundFunction< void , void , void , void , void , detail:: NonDefault > Args;
typedef typename detail:: InvokableImpl < R> :: template GlobalFunction< void , void , void , void , void , detail:: NonDefault > GCaller;
template < typename TObj, typename Constness>
struct MCaller{ typedef typename detail:: InvokableImpl < R> :: template MemberFunction< TObj, Constness> type; } ;
typedef std:: pair < detail:: Invokable < R> * ,detail:: DisconnectionPending > Slot;
typedef typename detail:: SlotContainer < Slot> :: type Slots;
typedef detail:: Mutex :: type Mutex_;
typedef detail:: ScopedLock :: type ScopedLock_;
bool isCurrentlyEmitting = false ;
Slots pendingConnects;
Slots slots;
Mutex_ slotsMutex;
} ;
} // namespace sisl
using namespace sisl;
struct TraficLight{
Signal< void ( ) > green;
Signal< void ( ) > red;
void switchToGreen( ) {
std:: cout << "===switching to green===\n " ;
green.emit ( ) ;
}
void switchToRed( ) {
std:: cout << "===switching to red===\n " ;
red.emit ( ) ;
}
} ;
struct Pedestrian{
void walk( ) { std:: cout << "Pedestrian walk\n " ; }
void wait( ) { std:: cout << "Pedestrian wait\n " ; }
} ;
int main( )
{
//create instances
TraficLight tl;
Pedestrian p;
//link
tl.green .connect ( p,& Pedestrian:: wait ) ;
tl.red .connect ( p,& Pedestrian:: walk ) ;
//begin operation
tl.switchToRed ( ) ;
tl.switchToGreen ( ) ;
return 0 ;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgoKCiNpbmNsdWRlIDx2ZWN0b3I+IC8vZm9yIGNvbnRhaW5lcnMKI2luY2x1ZGUgPGFsZ29yaXRobT4gLy9mb3IgcmVtb3ZlX2lmCiNpbmNsdWRlIDx1dGlsaXR5PiAgLy9mb3IgcGFpcgojaW5jbHVkZSA8Y2Fzc2VydD4KCm5hbWVzcGFjZSBzaXNsIHsgIC8vIHNpZ25hbCBzbG90CgpuYW1lc3BhY2UgZGV0YWlsIHsKCgoKLy89PT09PT09PT09PT09PXR5cGVzIGZvciBjdXN0b21pemF0aW9uPT09PT09PT09PT09PT09PT09PQoKdGVtcGxhdGUgPHR5cGVuYW1lIFRJbnZva2FibGU+CnN0cnVjdCBTbG90Q29udGFpbmVyIHsKICAgIHR5cGVkZWYgc3RkOjp2ZWN0b3I8VEludm9rYWJsZT4gdHlwZTsKfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBUUmVzdWx0PgpzdHJ1Y3QgUmV0dXJuVmFsdWVBZ2dyZWdhdGVDb250YWluZXJUeXBlIHsKICAgIHR5cGVkZWYgc3RkOjp2ZWN0b3I8VFJlc3VsdD4gdHlwZTsKfTsKCi8qKgogKiBAYnJpZWYgVGhlIExvY2tpbmdEaXNhYmxlZCBzdHJ1Y3QgaXMgYSBsb2NraW5nIGltcGxlbWVudGF0aW9uCiAqIHdoaWNoIGRvZXMgbm90aGluZyB3aGljaCBpcyB0aGUgZGVmYXVsdCBzeW5jaHJvbml6YXRpb24gYmVoYXZpb3VyLgogKi8Kc3RydWN0IExvY2tpbmdEaXNhYmxlZHsKICAgIHN0cnVjdCBNdXRleHt9OwogICAgc3RydWN0IFNjb3BlZExvY2t7U2NvcGVkTG9jayhNdXRleCBjb25zdCYpe319Owp9OwoKCnN0cnVjdCBTY29wZWRMb2NrewogICAgdHlwZWRlZiBMb2NraW5nRGlzYWJsZWQ6OlNjb3BlZExvY2sgdHlwZTsKfTsKCnN0cnVjdCBNdXRleHsKICAgIHR5cGVkZWYgTG9ja2luZ0Rpc2FibGVkOjpNdXRleCB0eXBlOwp9OwoKCgoKCgovKioKICogQGJyaWVmIEluc3RhbmNlcyBvZiB0aGlzIHN0cnVjdCByZXByZXNlbnQgdGhlIGFnZ3JlZ2F0ZWQgcmV0dXJuIHZhbHVlcwogKi8KdGVtcGxhdGUgPHR5cGVuYW1lIFI+CnN0cnVjdCBSZXR1cm5WYWx1ZUFnZ3JlZ2F0ZSB7CgogICAgdHlwZWRlZiB0eXBlbmFtZSBSZXR1cm5WYWx1ZUFnZ3JlZ2F0ZUNvbnRhaW5lclR5cGU8Uj46OnR5cGUgdHlwZTsKCiAgICBvcGVyYXRvciB0eXBlKCkgY29uc3QgeyByZXR1cm4gb3V0OyB9CgogICAgdHlwZSBvdXQ7Cn07Cgp0ZW1wbGF0ZSA8PgpzdHJ1Y3QgUmV0dXJuVmFsdWVBZ2dyZWdhdGU8dm9pZD4ge307CgoKCi8qKgogKiBAYnJpZWYgVGhpcyBpbnRlcmZhY2UgcmVwcmVzZW50cyBhbiBhYnN0cmFjdCBjYWxsLgogKi8KCnRlbXBsYXRlIDx0eXBlbmFtZSBSID0gdm9pZCwgdHlwZW5hbWUgQTEgPSB2b2lkLCB0eXBlbmFtZSBBMiA9IHZvaWQsIHR5cGVuYW1lIEEzID0gdm9pZCwgdHlwZW5hbWUgQTQgPSB2b2lkLCB0eXBlbmFtZSBBNSA9IHZvaWQ+CnN0cnVjdCBJbnZva2FibGU7Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgUiwgdHlwZW5hbWUgQTEsIHR5cGVuYW1lIEEyLCB0eXBlbmFtZSBBMywgdHlwZW5hbWUgQTQ+CnN0cnVjdCBJbnZva2FibGU8UiwgQTEsIEEyLCBBMywgQTQ+IHsKICAgIHZpcnR1YWwgUiBvcGVyYXRvcigpKEExLCBBMiwgQTMsIEE0KSA9IDA7CiAgICB2aXJ0dWFsIH5JbnZva2FibGUoKSB7fQp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFIsIHR5cGVuYW1lIEExLCB0eXBlbmFtZSBBMiwgdHlwZW5hbWUgQTM+CnN0cnVjdCBJbnZva2FibGU8UiwgQTEsIEEyLCBBMz4gewogICAgdmlydHVhbCBSIG9wZXJhdG9yKCkoQTEsIEEyLCBBMykgPSAwOwogICAgdmlydHVhbCB+SW52b2thYmxlKCkge30KfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBSLCB0eXBlbmFtZSBBMSwgdHlwZW5hbWUgQTI+CnN0cnVjdCBJbnZva2FibGU8UiwgQTEsIEEyPiB7CiAgICB2aXJ0dWFsIFIgb3BlcmF0b3IoKShBMSwgQTIpID0gMDsKICAgIHZpcnR1YWwgfkludm9rYWJsZSgpIHt9Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgUiwgdHlwZW5hbWUgQTE+CnN0cnVjdCBJbnZva2FibGU8UiwgQTE+IHsKICAgIHZpcnR1YWwgUiBvcGVyYXRvcigpKEExKSA9IDA7CiAgICB2aXJ0dWFsIH5JbnZva2FibGUoKSB7fQp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFI+CnN0cnVjdCBJbnZva2FibGU8Uj4gewogICAgdmlydHVhbCBSIG9wZXJhdG9yKCkoKSA9IDA7CiAgICB2aXJ0dWFsIH5JbnZva2FibGUoKSB7fQp9OwoKCgovLz09PT09PT09PT09PT09c3RydWN0IE1lbWJlckZ1bmM9PT09PT09PT09PT09PT09PT09CgpzdHJ1Y3QgQ29uc3R7fTsKc3RydWN0IE5vbkNvbnN0e307CgoKCi8qKgogKiBAYnJpZWYgVGhpcyBoZWxwZXIgY2xhc3MgZGVmaW5lcyB0aGUgdHlwZSBvZiBhIG1lbWJlciBmdW5jdGlvbiBzcGVjaWFsaXplZCBmb3IgY29uc3QgLyBub24tY29uc3QuCiAqLwp0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaiwgdHlwZW5hbWUgQ29uc3RuZXNzLCB0eXBlbmFtZSBSID0gdm9pZCwgdHlwZW5hbWUgQTEgPSB2b2lkLCB0eXBlbmFtZSBBMiA9IHZvaWQsIHR5cGVuYW1lIEEzID0gdm9pZCwgdHlwZW5hbWUgQTQgPSB2b2lkPgpzdHJ1Y3QgTWVtYmVyRnVuYzsKCnRlbXBsYXRlIDx0eXBlbmFtZSBUT2JqLCB0eXBlbmFtZSBSLCB0eXBlbmFtZSBBMSwgdHlwZW5hbWUgQTIsIHR5cGVuYW1lIEEzLCB0eXBlbmFtZSBBND4Kc3RydWN0IE1lbWJlckZ1bmM8VE9iaiwgTm9uQ29uc3QsIFIsIEExLCBBMiwgQTMsIEE0PiB7CiAgICB0eXBlZGVmIFIgKFRPYmo6Oip0eXBlKShBMSwgQTIsIEEzLCBBNCk7Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaiwgdHlwZW5hbWUgUiwgdHlwZW5hbWUgQTEsIHR5cGVuYW1lIEEyLCB0eXBlbmFtZSBBMz4Kc3RydWN0IE1lbWJlckZ1bmM8VE9iaiwgTm9uQ29uc3QsIFIsIEExLCBBMiwgQTM+IHsKICAgIHR5cGVkZWYgUiAoVE9iajo6KnR5cGUpKEExLCBBMiwgQTMpOwp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmosIHR5cGVuYW1lIFIsIHR5cGVuYW1lIEExLCB0eXBlbmFtZSBBMj4Kc3RydWN0IE1lbWJlckZ1bmM8VE9iaiwgTm9uQ29uc3QsIFIsIEExLCBBMj4gewogICAgdHlwZWRlZiBSIChUT2JqOjoqdHlwZSkoQTEsIEEyKTsKfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBUT2JqLCB0eXBlbmFtZSBSLCB0eXBlbmFtZSBBMT4Kc3RydWN0IE1lbWJlckZ1bmM8VE9iaiwgTm9uQ29uc3QsIFIsIEExPiB7CiAgICB0eXBlZGVmIFIgKFRPYmo6Oip0eXBlKShBMSk7Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgUiwgdHlwZW5hbWUgVE9iaj4Kc3RydWN0IE1lbWJlckZ1bmM8VE9iaiwgTm9uQ29uc3QsIFI+IHsKICAgIHR5cGVkZWYgUiAoVE9iajo6KnR5cGUpKCk7Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaiwgdHlwZW5hbWUgUiwgdHlwZW5hbWUgQTEsIHR5cGVuYW1lIEEyLCB0eXBlbmFtZSBBMywgdHlwZW5hbWUgQTQ+CnN0cnVjdCBNZW1iZXJGdW5jPFRPYmosIENvbnN0LCBSLCBBMSwgQTIsIEEzLCBBND4gewogICAgdHlwZWRlZiBSIChUT2JqOjoqdHlwZSkoQTEsIEEyLCBBMywgQTQpIGNvbnN0Owp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmosIHR5cGVuYW1lIFIsIHR5cGVuYW1lIEExLCB0eXBlbmFtZSBBMiwgdHlwZW5hbWUgQTM+CnN0cnVjdCBNZW1iZXJGdW5jPFRPYmosIENvbnN0LCBSLCBBMSwgQTIsIEEzPiB7CiAgICB0eXBlZGVmIFIgKFRPYmo6Oip0eXBlKShBMSwgQTIsIEEzKSBjb25zdDsKfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBUT2JqLCB0eXBlbmFtZSBSLCB0eXBlbmFtZSBBMSwgdHlwZW5hbWUgQTI+CnN0cnVjdCBNZW1iZXJGdW5jPFRPYmosIENvbnN0LCBSLCBBMSwgQTI+IHsKICAgIHR5cGVkZWYgUiAoVE9iajo6KnR5cGUpKEExLCBBMikgY29uc3Q7Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaiwgdHlwZW5hbWUgUiwgdHlwZW5hbWUgQTE+CnN0cnVjdCBNZW1iZXJGdW5jPFRPYmosIENvbnN0LCBSLCBBMT4gewogICAgdHlwZWRlZiBSIChUT2JqOjoqdHlwZSkoQTEpIGNvbnN0Owp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFIsIHR5cGVuYW1lIFRPYmo+CnN0cnVjdCBNZW1iZXJGdW5jPFRPYmosIENvbnN0LCBSPiB7CiAgICB0eXBlZGVmIFIgKFRPYmo6Oip0eXBlKSgpIGNvbnN0Owp9OwoKCnN0cnVjdCBEZWZhdWx0e307CnN0cnVjdCBOb25EZWZhdWx0e307Ci8vPT09PT09PT09PT09PT1zdHJ1Y3QgQ2FsbGFibGVJbXBsPT09PT09PT09PT09PT09PT09PQoKLyoqCiAqIEBicmllZiBUaGUgc3RydWN0IENhbGxhYmxlSW1wbCBjb250YWlucyBjb25yY3JldGUKICogaW1wbGVtZW50YXRpb25zIG9mIHRoZSBJbnZva2FibGUtaW5mZXJmYWNlIHNwZWNpYWxpemluZyB2b2lkIGFuZCBub24tdm9pZCBjYXNlcwogKi8KdGVtcGxhdGUgPHR5cGVuYW1lIFI+CnN0cnVjdCBJbnZva2FibGVJbXBsIHsKCiAgICB0eXBlZGVmIFIgUl87CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIEExID0gdm9pZCwgdHlwZW5hbWUgQTIgPSB2b2lkLCB0eXBlbmFtZSBBMyA9IHZvaWQsIHR5cGVuYW1lIEE0ID0gdm9pZCwgdHlwZW5hbWUgQTUgPSB2b2lkLCB0eXBlbmFtZSBpc0RlZmF1bHQgPSBEZWZhdWx0PgogICAgc3RydWN0IEdsb2JhbEZ1bmN0aW9uOwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBBMSwgdHlwZW5hbWUgQTIsIHR5cGVuYW1lIEEzLCB0eXBlbmFtZSBBND4KICAgIHN0cnVjdCBHbG9iYWxGdW5jdGlvbjxBMSwgQTIsIEEzLCBBND4gOiBwdWJsaWMgSW52b2thYmxlPFJfLCBBMSwgQTIsIEEzLCBBND4gewogICAgICAgIHR5cGVkZWYgR2xvYmFsRnVuY3Rpb248QTEsIEEyLCBBMywgQTQ+IENsYXNzdHlwZTsKICAgICAgICB0eXBlZGVmIEludm9rYWJsZTxSXywgQTEsIEEyLCBBMywgQTQ+IFN1cGVyY2xhc3M7CiAgICAgICAgdHlwZWRlZiBSXyAoKk1lbWJlcikoQTEsIEEyLCBBMywgQTQpOwogICAgICAgIHZpcnR1YWwgUl8gb3BlcmF0b3IoKShBMSBhMSwgQTIgYTIsIEEzIGEzLCBBNCBhNCkgeyByZXR1cm4gbV9tZW1iZXIoYTEsIGEyLCBhMywgYTQpOyB9CiAgICAgICAgR2xvYmFsRnVuY3Rpb24oTWVtYmVyIG1lbWJlcikgOiBtX21lbWJlcihtZW1iZXIpIHt9CiAgICAgICAgYm9vbCBpc0VxdWFsKENsYXNzdHlwZSBjb25zdCYgb3RoZXIpY29uc3R7IHJldHVybiBtX21lbWJlciA9PSBvdGhlci5tX21lbWJlcjt9CiAgICBwcml2YXRlOgogICAgICAgIE1lbWJlciBtX21lbWJlcjsKICAgIH07CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIEExLCB0eXBlbmFtZSBBMiwgdHlwZW5hbWUgQTM+CiAgICBzdHJ1Y3QgR2xvYmFsRnVuY3Rpb248QTEsIEEyLCBBMz4gOiBwdWJsaWMgSW52b2thYmxlPFJfLCBBMSwgQTIsIEEzPiB7CiAgICAgICAgdHlwZWRlZiBHbG9iYWxGdW5jdGlvbjxBMSwgQTIsIEEzPiBDbGFzc3R5cGU7CiAgICAgICAgdHlwZWRlZiBJbnZva2FibGU8Ul8sIEExLCBBMiwgQTM+IFN1cGVyY2xhc3M7CiAgICAgICAgdHlwZWRlZiBSXyAoKk1lbWJlcikoQTEsIEEyLCBBMyk7CiAgICAgICAgdmlydHVhbCBSXyBvcGVyYXRvcigpKEExIGExLCBBMiBhMiwgQTMgYTMpIHsgcmV0dXJuIG1fbWVtYmVyKGExLCBhMiwgYTMpOyB9CiAgICAgICAgR2xvYmFsRnVuY3Rpb24oTWVtYmVyIG1lbWJlcikgOiBtX21lbWJlcihtZW1iZXIpIHt9CiAgICAgICAgYm9vbCBpc0VxdWFsKENsYXNzdHlwZSBjb25zdCYgb3RoZXIpY29uc3R7IHJldHVybiBtX21lbWJlciA9PSBvdGhlci5tX21lbWJlcjt9CiAgICBwcml2YXRlOgogICAgICAgIE1lbWJlciBtX21lbWJlcjsKICAgIH07CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIEExLCB0eXBlbmFtZSBBMj4KICAgIHN0cnVjdCBHbG9iYWxGdW5jdGlvbjxBMSwgQTI+IDogcHVibGljIEludm9rYWJsZTxSXywgQTEsIEEyPiB7CiAgICAgICAgdHlwZWRlZiBHbG9iYWxGdW5jdGlvbjxBMSwgQTI+IENsYXNzdHlwZTsKICAgICAgICB0eXBlZGVmIEludm9rYWJsZTxSXywgQTEsIEEyPiBTdXBlcmNsYXNzOwogICAgICAgIHR5cGVkZWYgUl8gKCpNZW1iZXIpKEExLCBBMik7CiAgICAgICAgdmlydHVhbCBSXyBvcGVyYXRvcigpKEExIGExLCBBMiBhMikgeyByZXR1cm4gbV9tZW1iZXIoYTEsIGEyKTsgfQogICAgICAgIEdsb2JhbEZ1bmN0aW9uKE1lbWJlciBtZW1iZXIpIDogbV9tZW1iZXIobWVtYmVyKSB7fQogICAgICAgIGJvb2wgaXNFcXVhbChDbGFzc3R5cGUgY29uc3QmIG90aGVyKWNvbnN0eyByZXR1cm4gbV9tZW1iZXIgPT0gb3RoZXIubV9tZW1iZXI7fQogICAgcHJpdmF0ZToKICAgICAgICBNZW1iZXIgbV9tZW1iZXI7CiAgICB9OwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBBMT4KICAgIHN0cnVjdCBHbG9iYWxGdW5jdGlvbjxBMT4gOiBwdWJsaWMgSW52b2thYmxlPFJfLCBBMT4gewogICAgICAgIHR5cGVkZWYgR2xvYmFsRnVuY3Rpb248QTE+IENsYXNzdHlwZTsKICAgICAgICB0eXBlZGVmIEludm9rYWJsZTxSXywgQTE+IFN1cGVyY2xhc3M7CiAgICAgICAgdHlwZWRlZiBSXyAoKk1lbWJlcikoQTEpOwogICAgICAgIHZpcnR1YWwgUl8gb3BlcmF0b3IoKShBMSBhMSkgeyByZXR1cm4gbV9tZW1iZXIoYTEpOyB9CiAgICAgICAgR2xvYmFsRnVuY3Rpb24oTWVtYmVyIG1lbWJlcikgOiBtX21lbWJlcihtZW1iZXIpIHt9CiAgICAgICAgYm9vbCBpc0VxdWFsKENsYXNzdHlwZSBjb25zdCYgb3RoZXIpY29uc3R7IHJldHVybiBtX21lbWJlciA9PSBvdGhlci5tX21lbWJlcjt9CiAgICBwcml2YXRlOgogICAgICAgIE1lbWJlciBtX21lbWJlcjsKICAgIH07CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIGlzRGVmYXVsdD4gIC8vIG11c3QgaGF2ZSBhdCBsZWFzdCBvbmUgdGVtcGxhdGUgcGFyYW1ldGVyIHRvIGNvbXBpbGUhCiAgICBzdHJ1Y3QgR2xvYmFsRnVuY3Rpb248dm9pZCwgdm9pZCwgdm9pZCwgdm9pZCwgdm9pZCwgaXNEZWZhdWx0PiA6IHB1YmxpYyBJbnZva2FibGU8Ul8+IHsgLy9tdXN0IGJlIG5vbi1kZWZhdWx0IQogICAgICAgIHR5cGVkZWYgR2xvYmFsRnVuY3Rpb248dm9pZCwgdm9pZCwgdm9pZCwgdm9pZCwgdm9pZCwgaXNEZWZhdWx0PiBDbGFzc3R5cGU7CiAgICAgICAgdHlwZWRlZiBJbnZva2FibGU8Ul8+IFN1cGVyY2xhc3M7CiAgICAgICAgdHlwZWRlZiBSXyAoKk1lbWJlcikoKTsKICAgICAgICB2aXJ0dWFsIFJfIG9wZXJhdG9yKCkoKSB7IHJldHVybiBtX21lbWJlcigpOyB9CiAgICAgICAgR2xvYmFsRnVuY3Rpb24oTWVtYmVyIG1lbWJlcikgOiBtX21lbWJlcihtZW1iZXIpIHt9CiAgICAgICAgYm9vbCBpc0VxdWFsKENsYXNzdHlwZSBjb25zdCYgb3RoZXIpY29uc3R7IHJldHVybiBtX21lbWJlciA9PSBvdGhlci5tX21lbWJlcjt9CiAgICBwcml2YXRlOgogICAgICAgIE1lbWJlciBtX21lbWJlcjsKICAgIH07CgoKCgogICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmosIHR5cGVuYW1lIENvbnN0bmVzcywgdHlwZW5hbWUgQTEgPSB2b2lkLCB0eXBlbmFtZSBBMiA9IHZvaWQsIHR5cGVuYW1lIEEzID0gdm9pZCwgdHlwZW5hbWUgQTQgPSB2b2lkLCB0eXBlbmFtZSBBNSA9IHZvaWQ+CiAgICBzdHJ1Y3QgTWVtYmVyRnVuY3Rpb247CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmosIHR5cGVuYW1lIENvbnN0bmVzcywgdHlwZW5hbWUgQTEsIHR5cGVuYW1lIEEyLCB0eXBlbmFtZSBBMywgdHlwZW5hbWUgQTQ+CiAgICBzdHJ1Y3QgTWVtYmVyRnVuY3Rpb248VE9iaiwgQ29uc3RuZXNzLCBBMSwgQTIsIEEzLCBBND4gOiBwdWJsaWMgSW52b2thYmxlPFJfLCBBMSwgQTIsIEEzLCBBND4gewoKICAgICAgICB0eXBlZGVmIE1lbWJlckZ1bmN0aW9uPFRPYmosIENvbnN0bmVzcywgQTEsIEEyLCBBMywgQTQ+IENsYXNzdHlwZTsKICAgICAgICB0eXBlZGVmIEludm9rYWJsZTxSXywgQTEsIEEyLCBBMywgQTQ+IFN1cGVyY2xhc3M7CgogICAgICAgIHR5cGVkZWYgdHlwZW5hbWUgTWVtYmVyRnVuYzxUT2JqLCBDb25zdG5lc3MsIFJfLCBBMSwgQTIsIEEzLCBBND46OnR5cGUgTWVtYmVyOwoKICAgICAgICB2aXJ0dWFsIFJfIG9wZXJhdG9yKCkoQTEgYTEsIEEyIGEyLCBBMyBhMywgQTQgYTQpIHsgcmV0dXJuIChtX29iai4qbV9tZW1iZXIpKGExLCBhMiwgYTMsIGE0KTsgfQoKICAgICAgICBNZW1iZXJGdW5jdGlvbihUT2JqJiBvYmosIE1lbWJlciBtZW1iZXIpIDogbV9vYmoob2JqKSwgbV9tZW1iZXIobWVtYmVyKSB7fQoKICAgICAgICBib29sIGlzRXF1YWwoQ2xhc3N0eXBlIGNvbnN0JiBvdGhlciljb25zdHsKICAgICAgICAgICAgcmV0dXJuICgmbV9vYmogPT0gJihvdGhlci5tX29iaikpICYmIChtX21lbWJlciA9PSBvdGhlci5tX21lbWJlcik7CiAgICAgICAgfQogICAgcHJpdmF0ZToKCiAgICAgICAgVE9iaiYgbV9vYmo7CiAgICAgICAgTWVtYmVyIG1fbWVtYmVyOwogICAgfTsKCgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmosIHR5cGVuYW1lIENvbnN0bmVzcywgdHlwZW5hbWUgQTEsIHR5cGVuYW1lIEEyLCB0eXBlbmFtZSBBMz4KICAgIHN0cnVjdCBNZW1iZXJGdW5jdGlvbjxUT2JqLCBDb25zdG5lc3MsIEExLCBBMiwgQTM+IDogcHVibGljIEludm9rYWJsZTxSXywgQTEsIEEyLCBBMz4gewoKICAgICAgICB0eXBlZGVmIE1lbWJlckZ1bmN0aW9uPFRPYmosIENvbnN0bmVzcywgQTEsIEEyLCBBMz4gQ2xhc3N0eXBlOwogICAgICAgIHR5cGVkZWYgSW52b2thYmxlPFJfLCBBMSwgQTIsIEEzPiBTdXBlcmNsYXNzOwoKICAgICAgICB0eXBlZGVmIHR5cGVuYW1lIE1lbWJlckZ1bmM8VE9iaiwgQ29uc3RuZXNzLCBSXywgQTEsIEEyLCBBMz46OnR5cGUgTWVtYmVyOwoKICAgICAgICB2aXJ0dWFsIFJfIG9wZXJhdG9yKCkoQTEgYTEsIEEyIGEyLCBBMyBhMykgeyByZXR1cm4gKG1fb2JqLiptX21lbWJlcikoYTEsIGEyLCBhMyk7IH0KCiAgICAgICAgTWVtYmVyRnVuY3Rpb24oVE9iaiYgb2JqLCBNZW1iZXIgbWVtYmVyKSA6IG1fb2JqKG9iaiksIG1fbWVtYmVyKG1lbWJlcikge30KCiAgICAgICAgYm9vbCBpc0VxdWFsKENsYXNzdHlwZSBjb25zdCYgb3RoZXIpY29uc3R7CiAgICAgICAgICAgIHJldHVybiAoJm1fb2JqID09ICYob3RoZXIubV9vYmopKSAmJiAobV9tZW1iZXIgPT0gb3RoZXIubV9tZW1iZXIpOwogICAgICAgIH0KICAgIHByaXZhdGU6CgogICAgICAgIFRPYmomIG1fb2JqOwogICAgICAgIE1lbWJlciBtX21lbWJlcjsKICAgIH07CiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaiwgdHlwZW5hbWUgQ29uc3RuZXNzLCB0eXBlbmFtZSBBMSwgdHlwZW5hbWUgQTI+CiAgICBzdHJ1Y3QgTWVtYmVyRnVuY3Rpb248VE9iaiwgQ29uc3RuZXNzLCBBMSwgQTI+IDogcHVibGljIEludm9rYWJsZTxSXywgQTEsIEEyPiB7CgogICAgICAgIHR5cGVkZWYgTWVtYmVyRnVuY3Rpb248VE9iaiwgQ29uc3RuZXNzLCBBMSwgQTI+IENsYXNzdHlwZTsKICAgICAgICB0eXBlZGVmIEludm9rYWJsZTxSXywgQTEsIEEyPiBTdXBlcmNsYXNzOwogICAgICAgIHR5cGVkZWYgdHlwZW5hbWUgTWVtYmVyRnVuYzxUT2JqLCBDb25zdG5lc3MsIFJfLCBBMSwgQTI+Ojp0eXBlIE1lbWJlcjsKCiAgICAgICAgdmlydHVhbCBSXyBvcGVyYXRvcigpKEExIGExLCBBMiBhMikgeyByZXR1cm4gKG1fb2JqLiptX21lbWJlcikoYTEsIGEyKTsgfQoKICAgICAgICBNZW1iZXJGdW5jdGlvbihUT2JqJiBvYmosIE1lbWJlciBtZW1iZXIpIDogbV9vYmoob2JqKSwgbV9tZW1iZXIobWVtYmVyKSB7fQoKICAgICAgICBib29sIGlzRXF1YWwoQ2xhc3N0eXBlIGNvbnN0JiBvdGhlciljb25zdHsKICAgICAgICAgICAgcmV0dXJuICgmbV9vYmogPT0gJihvdGhlci5tX29iaikpICYmIChtX21lbWJlciA9PSBvdGhlci5tX21lbWJlcik7CiAgICAgICAgfQogICAgcHJpdmF0ZToKCiAgICAgICAgVE9iaiYgbV9vYmo7CiAgICAgICAgTWVtYmVyIG1fbWVtYmVyOwogICAgfTsKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUT2JqLCB0eXBlbmFtZSBDb25zdG5lc3MsIHR5cGVuYW1lIEExPgogICAgc3RydWN0IE1lbWJlckZ1bmN0aW9uPFRPYmosIENvbnN0bmVzcywgQTE+IDogcHVibGljIEludm9rYWJsZTxSXywgQTE+IHsKCiAgICAgICAgdHlwZWRlZiBNZW1iZXJGdW5jdGlvbjxUT2JqLCBDb25zdG5lc3MsIEExPiBDbGFzc3R5cGU7CiAgICAgICAgdHlwZWRlZiBJbnZva2FibGU8Ul8sIEExPiBTdXBlcmNsYXNzOwoKICAgICAgICB0eXBlZGVmIHR5cGVuYW1lIE1lbWJlckZ1bmM8VE9iaiwgQ29uc3RuZXNzLCBSXywgQTE+Ojp0eXBlIE1lbWJlcjsKCiAgICAgICAgdmlydHVhbCBSXyBvcGVyYXRvcigpKEExIGExKSB7IHJldHVybiAobV9vYmouKm1fbWVtYmVyKShhMSk7IH0KCiAgICAgICAgTWVtYmVyRnVuY3Rpb24oVE9iaiYgb2JqLCBNZW1iZXIgbWVtYmVyKSA6IG1fb2JqKG9iaiksIG1fbWVtYmVyKG1lbWJlcikge30KCiAgICAgICAgYm9vbCBpc0VxdWFsKENsYXNzdHlwZSBjb25zdCYgb3RoZXIpY29uc3R7CiAgICAgICAgICAgIHJldHVybiAoJm1fb2JqID09ICYob3RoZXIubV9vYmopKSAmJiAobV9tZW1iZXIgPT0gb3RoZXIubV9tZW1iZXIpOwogICAgICAgIH0KICAgIHByaXZhdGU6CgogICAgICAgIFRPYmomIG1fb2JqOwogICAgICAgIE1lbWJlciBtX21lbWJlcjsKICAgIH07CiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaiwgdHlwZW5hbWUgQ29uc3RuZXNzPgogICAgc3RydWN0IE1lbWJlckZ1bmN0aW9uPFRPYmosIENvbnN0bmVzcz4gOiBwdWJsaWMgSW52b2thYmxlPFJfPiB7CgogICAgICAgIHR5cGVkZWYgTWVtYmVyRnVuY3Rpb248VE9iaiwgQ29uc3RuZXNzPiBDbGFzc3R5cGU7CiAgICAgICAgdHlwZWRlZiBJbnZva2FibGU8Ul8+IFN1cGVyY2xhc3M7CgogICAgICAgIHR5cGVkZWYgdHlwZW5hbWUgTWVtYmVyRnVuYzxUT2JqLCBDb25zdG5lc3MsIFJfPjo6dHlwZSBNZW1iZXI7CgogICAgICAgIHZpcnR1YWwgUl8gb3BlcmF0b3IoKSgpIHsgcmV0dXJuIChtX29iai4qbV9tZW1iZXIpKCk7IH0KCiAgICAgICAgTWVtYmVyRnVuY3Rpb24oVE9iaiYgb2JqLCBNZW1iZXIgbWVtYmVyKSA6IG1fb2JqKG9iaiksIG1fbWVtYmVyKG1lbWJlcikge30KCiAgICAgICAgYm9vbCBpc0VxdWFsKENsYXNzdHlwZSBjb25zdCYgb3RoZXIpY29uc3R7CiAgICAgICAgICAgIHJldHVybiAoJm1fb2JqID09ICYob3RoZXIubV9vYmopKSAmJiAobV9tZW1iZXIgPT0gb3RoZXIubV9tZW1iZXIpOwogICAgICAgIH0KCiAgICBwcml2YXRlOgogICAgICAgIFRPYmomIG1fb2JqOwogICAgICAgIE1lbWJlciBtX21lbWJlcjsKICAgIH07CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIEExID0gdm9pZCwgdHlwZW5hbWUgQTIgPSB2b2lkLCB0eXBlbmFtZSBBMyA9IHZvaWQsIHR5cGVuYW1lIEE0ID0gdm9pZCwgdHlwZW5hbWUgQTUgPSB2b2lkLCB0eXBlbmFtZSBpc0RlZmF1bHQgPSBEZWZhdWx0PgogICAgc3RydWN0IEJvdW5kRnVuY3Rpb247CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIEExLCB0eXBlbmFtZSBBMiwgdHlwZW5hbWUgQTMsIHR5cGVuYW1lIEE0PgogICAgc3RydWN0IEJvdW5kRnVuY3Rpb248QTEsIEEyLCBBMywgQTQ+IHsKICAgICAgICBBMSBhMTsKICAgICAgICBBMiBhMjsKICAgICAgICBBMyBhMzsKICAgICAgICBBNCBhNDsKICAgICAgICBCb3VuZEZ1bmN0aW9uKEExIGExXywgQTIgYTJfLCBBMyBhM18sIEE0IGE0Xyk6YTEoYTFfKSxhMihhMl8pLGEzKGEzXyksYTQoYTRfKXt9CiAgICAgICAgdmlydHVhbCBSXyBvcGVyYXRvcigpKEludm9rYWJsZTxSXyxBMSwgQTIsIEEzLCBBND4mIGludm9rYWJsZSkgeyByZXR1cm4gaW52b2thYmxlKGExLGEyLGEzLGE0KTsgfQogICAgfTsKCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgQTEsIHR5cGVuYW1lIEEyLCB0eXBlbmFtZSBBMz4KICAgIHN0cnVjdCBCb3VuZEZ1bmN0aW9uPEExLCBBMiwgQTM+IHsKICAgICAgICBBMSBhMTsKICAgICAgICBBMiBhMjsKICAgICAgICBBMyBhMzsKICAgICAgICBCb3VuZEZ1bmN0aW9uKEExIGExXywgQTIgYTJfLCBBMyBhM18pOmExKGExXyksYTIoYTJfKSxhMyhhM18pe30KICAgICAgICB2aXJ0dWFsIFJfIG9wZXJhdG9yKCkoSW52b2thYmxlPFJfLEExLCBBMiwgQTM+JiBpbnZva2FibGUpIHsgcmV0dXJuIGludm9rYWJsZShhMSxhMixhMyk7IH0KICAgIH07CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIEExLCB0eXBlbmFtZSBBMj4KICAgIHN0cnVjdCBCb3VuZEZ1bmN0aW9uPEExLCBBMj4gewogICAgICAgIEExIGExOwogICAgICAgIEEyIGEyOwogICAgICAgIEJvdW5kRnVuY3Rpb24oQTEgYTFfLCBBMiBhMl8pOmExKGExXyksYTIoYTJfKXt9CiAgICAgICAgdmlydHVhbCBSXyBvcGVyYXRvcigpKEludm9rYWJsZTxSXyxBMSwgQTI+JiBpbnZva2FibGUpIHsgcmV0dXJuIGludm9rYWJsZShhMSxhMik7IH0KICAgIH07CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIEExPgogICAgc3RydWN0IEJvdW5kRnVuY3Rpb248QTE+IHsKICAgICAgICBBMSBhMTsKICAgICAgICBCb3VuZEZ1bmN0aW9uKEExIGExXyk6YTEoYTFfKXt9CiAgICAgICAgdmlydHVhbCBSXyBvcGVyYXRvcigpKEludm9rYWJsZTxSXyxBMT4mIGludm9rYWJsZSkgeyByZXR1cm4gaW52b2thYmxlKGExKTsgfQogICAgfTsKCiAgICB0ZW1wbGF0ZTx0eXBlbmFtZSBpc0RlZmF1bHQ+ICAvLyBtdXN0IGhhdmUgYXQgbGVhc3Qgb25lIHRlbXBsYXRlIHBhcmFtZXRlciB0byBjb21waWxlIQogICAgc3RydWN0IEJvdW5kRnVuY3Rpb248dm9pZCx2b2lkLHZvaWQsdm9pZCx2b2lkLGlzRGVmYXVsdD4gewogICAgICAgIEJvdW5kRnVuY3Rpb24oKXt9CiAgICAgICAgdmlydHVhbCBSXyBvcGVyYXRvcigpKEludm9rYWJsZTxSXz4mIGludm9rYWJsZSkgeyByZXR1cm4gaW52b2thYmxlKCk7IH0KICAgIH07Cn07CnRlbXBsYXRlIDw+CnN0cnVjdCBJbnZva2FibGVJbXBsPHZvaWQ+IHsKCiAgICB0eXBlZGVmIHZvaWQgUl87CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIEExID0gdm9pZCwgdHlwZW5hbWUgQTIgPSB2b2lkLCB0eXBlbmFtZSBBMyA9IHZvaWQsIHR5cGVuYW1lIEE0ID0gdm9pZCwgdHlwZW5hbWUgQTUgPSB2b2lkLCB0eXBlbmFtZSBpc0RlZmF1bHQgPSBEZWZhdWx0PgogICAgc3RydWN0IEdsb2JhbEZ1bmN0aW9uOwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBBMSwgdHlwZW5hbWUgQTIsIHR5cGVuYW1lIEEzLCB0eXBlbmFtZSBBND4KICAgIHN0cnVjdCBHbG9iYWxGdW5jdGlvbjxBMSwgQTIsIEEzLCBBND4gOiBwdWJsaWMgSW52b2thYmxlPFJfLCBBMSwgQTIsIEEzLCBBND4gewoKICAgICAgICB0eXBlZGVmIEdsb2JhbEZ1bmN0aW9uPEExLCBBMiwgQTMsIEE0PiBDbGFzc3R5cGU7CiAgICAgICAgdHlwZWRlZiBJbnZva2FibGU8Ul8sIEExLCBBMiwgQTMsIEE0PiBTdXBlcmNsYXNzOwoKICAgICAgICB0eXBlZGVmIFJfICgqTWVtYmVyKShBMSwgQTIsIEEzLCBBNCk7CgogICAgICAgIHZpcnR1YWwgUl8gb3BlcmF0b3IoKShBMSBhMSwgQTIgYTIsIEEzIGEzLCBBNCBhNCkgeyBtX21lbWJlcihhMSwgYTIsIGEzLCBhNCk7IH0KCiAgICAgICAgYm9vbCBpc0VxdWFsKENsYXNzdHlwZSBjb25zdCYgb3RoZXIpY29uc3R7IHJldHVybiBtX21lbWJlciA9PSBvdGhlci5tX21lbWJlcjt9CgogICAgICAgIEdsb2JhbEZ1bmN0aW9uKE1lbWJlciBtZW1iZXIpIDogbV9tZW1iZXIobWVtYmVyKSB7fQoKICAgIHByaXZhdGU6CiAgICAgICAgTWVtYmVyIG1fbWVtYmVyOwogICAgfTsKCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgQTEsIHR5cGVuYW1lIEEyLCB0eXBlbmFtZSBBMz4KICAgIHN0cnVjdCBHbG9iYWxGdW5jdGlvbjxBMSwgQTIsIEEzPiA6IHB1YmxpYyBJbnZva2FibGU8Ul8sIEExLCBBMiwgQTM+IHsKCiAgICAgICAgdHlwZWRlZiBHbG9iYWxGdW5jdGlvbjxBMSwgQTIsIEEzPiBDbGFzc3R5cGU7CiAgICAgICAgdHlwZWRlZiBJbnZva2FibGU8Ul8sIEExLCBBMiwgQTM+IFN1cGVyY2xhc3M7CgogICAgICAgIHR5cGVkZWYgUl8gKCpNZW1iZXIpKEExLCBBMiwgQTMpOwoKICAgICAgICB2aXJ0dWFsIFJfIG9wZXJhdG9yKCkoQTEgYTEsIEEyIGEyLCBBMyBhMykgeyBtX21lbWJlcihhMSwgYTIsIGEzKTsgfQoKICAgICAgICBHbG9iYWxGdW5jdGlvbihNZW1iZXIgbWVtYmVyKSA6IG1fbWVtYmVyKG1lbWJlcikge30KCiAgICAgICAgYm9vbCBpc0VxdWFsKENsYXNzdHlwZSBjb25zdCYgb3RoZXIpY29uc3R7IHJldHVybiBtX21lbWJlciA9PSBvdGhlci5tX21lbWJlcjt9CgogICAgcHJpdmF0ZToKICAgICAgICBNZW1iZXIgbV9tZW1iZXI7CiAgICB9OwogICAgdGVtcGxhdGUgPHR5cGVuYW1lIEExLCB0eXBlbmFtZSBBMj4KICAgIHN0cnVjdCBHbG9iYWxGdW5jdGlvbjxBMSwgQTI+IDogcHVibGljIEludm9rYWJsZTxSXywgQTEsIEEyPiB7CgogICAgICAgIHR5cGVkZWYgR2xvYmFsRnVuY3Rpb248QTEsIEEyPiBDbGFzc3R5cGU7CiAgICAgICAgdHlwZWRlZiBJbnZva2FibGU8Ul8sIEExLCBBMj4gU3VwZXJjbGFzczsKCiAgICAgICAgdHlwZWRlZiBSXyAoKk1lbWJlcikoQTEsIEEyKTsKCiAgICAgICAgdmlydHVhbCBSXyBvcGVyYXRvcigpKEExIGExLCBBMiBhMikgeyBtX21lbWJlcihhMSwgYTIpOyB9CgogICAgICAgIEdsb2JhbEZ1bmN0aW9uKE1lbWJlciBtZW1iZXIpIDogbV9tZW1iZXIobWVtYmVyKSB7fQoKICAgICAgICBib29sIGlzRXF1YWwoQ2xhc3N0eXBlIGNvbnN0JiBvdGhlciljb25zdHsgcmV0dXJuIG1fbWVtYmVyID09IG90aGVyLm1fbWVtYmVyO30KCiAgICBwcml2YXRlOgogICAgICAgIE1lbWJlciBtX21lbWJlcjsKCiAgICB9OwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBBMT4KICAgIHN0cnVjdCBHbG9iYWxGdW5jdGlvbjxBMT4gOiBwdWJsaWMgSW52b2thYmxlPFJfLCBBMT4gewoKICAgICAgICB0eXBlZGVmIEdsb2JhbEZ1bmN0aW9uPEExPiBDbGFzc3R5cGU7CiAgICAgICAgdHlwZWRlZiBJbnZva2FibGU8Ul8sIEExPiBTdXBlcmNsYXNzOwoKICAgICAgICB0eXBlZGVmIFJfICgqTWVtYmVyKShBMSk7CgogICAgICAgIHZpcnR1YWwgUl8gb3BlcmF0b3IoKShBMSBhMSkgeyBtX21lbWJlcihhMSk7IH0KCiAgICAgICAgR2xvYmFsRnVuY3Rpb24oTWVtYmVyIG1lbWJlcikgOiBtX21lbWJlcihtZW1iZXIpIHt9CgogICAgICAgIGJvb2wgaXNFcXVhbChDbGFzc3R5cGUgY29uc3QmIG90aGVyKWNvbnN0eyByZXR1cm4gbV9tZW1iZXIgPT0gb3RoZXIubV9tZW1iZXI7fQoKICAgIHByaXZhdGU6CiAgICAgICAgTWVtYmVyIG1fbWVtYmVyOwogICAgfTsKCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgaXNEZWZhdWx0PiAgLy8gbXVzdCBoYXZlIGF0IGxlYXN0IG9uZSB0ZW1wbGF0ZSBwYXJhbWV0ZXIgdG8gY29tcGlsZSEKICAgIHN0cnVjdCBHbG9iYWxGdW5jdGlvbjx2b2lkLCB2b2lkLCB2b2lkLCB2b2lkLCB2b2lkLCBpc0RlZmF1bHQ+IDogcHVibGljIEludm9rYWJsZTxSXz4geyAvL211c3QgYmUgbm9uRGVmYXVsdAoKICAgICAgICB0eXBlZGVmIEdsb2JhbEZ1bmN0aW9uPHZvaWQsIHZvaWQsIHZvaWQsIHZvaWQsIHZvaWQsIGlzRGVmYXVsdD4gQ2xhc3N0eXBlOwogICAgICAgIHR5cGVkZWYgSW52b2thYmxlPFJfPiBTdXBlcmNsYXNzOwoKICAgICAgICB0eXBlZGVmIFJfICgqTWVtYmVyKSgpOwoKICAgICAgICB2aXJ0dWFsIFJfIG9wZXJhdG9yKCkoKSB7IG1fbWVtYmVyKCk7IH0KCiAgICAgICAgR2xvYmFsRnVuY3Rpb24oTWVtYmVyIG1lbWJlcikgOiBtX21lbWJlcihtZW1iZXIpIHt9CgogICAgICAgIGJvb2wgaXNFcXVhbChDbGFzc3R5cGUgY29uc3QmIG90aGVyKWNvbnN0eyByZXR1cm4gbV9tZW1iZXIgPT0gb3RoZXIubV9tZW1iZXI7fQoKICAgIHByaXZhdGU6CiAgICAgICAgTWVtYmVyIG1fbWVtYmVyOwogICAgfTsKCgogICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwoKCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaiwgdHlwZW5hbWUgQ29uc3RuZXNzLCB0eXBlbmFtZSBBMSA9IHZvaWQsIHR5cGVuYW1lIEEyID0gdm9pZCwgdHlwZW5hbWUgQTMgPSB2b2lkLCB0eXBlbmFtZSBBNCA9IHZvaWQsIHR5cGVuYW1lIEE1ID0gdm9pZD4KICAgIHN0cnVjdCBNZW1iZXJGdW5jdGlvbjsKCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaiwgdHlwZW5hbWUgQ29uc3RuZXNzLCB0eXBlbmFtZSBBMSwgdHlwZW5hbWUgQTIsIHR5cGVuYW1lIEEzLCB0eXBlbmFtZSBBND4KICAgIHN0cnVjdCBNZW1iZXJGdW5jdGlvbjxUT2JqLCBDb25zdG5lc3MsIEExLCBBMiwgQTMsIEE0PiA6IHB1YmxpYyBJbnZva2FibGU8Ul8sIEExLCBBMiwgQTMsIEE0PiB7CgogICAgICAgIHR5cGVkZWYgTWVtYmVyRnVuY3Rpb248VE9iaiwgQ29uc3RuZXNzLCBBMSwgQTIsIEEzLCBBND4gQ2xhc3N0eXBlOwogICAgICAgIHR5cGVkZWYgSW52b2thYmxlPFJfLCBBMSwgQTIsIEEzLCBBND4gU3VwZXJjbGFzczsKCiAgICAgICAgdHlwZWRlZiB0eXBlbmFtZSBNZW1iZXJGdW5jPFRPYmosIENvbnN0bmVzcywgUl8sIEExLCBBMiwgQTMsIEE0Pjo6dHlwZSBNZW1iZXI7CgogICAgICAgIHZpcnR1YWwgUl8gb3BlcmF0b3IoKShBMSBhMSwgQTIgYTIsIEEzIGEzLCBBNCBhNCkgeyAobV9vYmouKm1fbWVtYmVyKShhMSwgYTIsIGEzLCBhNCk7IH0KCiAgICAgICAgTWVtYmVyRnVuY3Rpb24oVE9iaiYgb2JqLCBNZW1iZXIgbWVtYmVyKSA6IG1fb2JqKG9iaiksIG1fbWVtYmVyKG1lbWJlcikge30KCiAgICAgICAgYm9vbCBpc0VxdWFsKENsYXNzdHlwZSBjb25zdCYgb3RoZXIpY29uc3R7CiAgICAgICAgICAgIHJldHVybiAoJm1fb2JqID09ICYob3RoZXIubV9vYmopKSAmJiAobV9tZW1iZXIgPT0gb3RoZXIubV9tZW1iZXIpOwogICAgICAgIH0KCiAgICBwcml2YXRlOgogICAgICAgIFRPYmomIG1fb2JqOwogICAgICAgIE1lbWJlciBtX21lbWJlcjsKICAgIH07CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmosIHR5cGVuYW1lIENvbnN0bmVzcywgdHlwZW5hbWUgQTEsIHR5cGVuYW1lIEEyLCB0eXBlbmFtZSBBMz4KICAgIHN0cnVjdCBNZW1iZXJGdW5jdGlvbjxUT2JqLCBDb25zdG5lc3MsIEExLCBBMiwgQTM+IDogcHVibGljIEludm9rYWJsZTxSXywgQTEsIEEyLCBBMz4gewoKICAgICAgICB0eXBlZGVmIE1lbWJlckZ1bmN0aW9uPFRPYmosIENvbnN0bmVzcywgQTEsIEEyLCBBMz4gQ2xhc3N0eXBlOwogICAgICAgIHR5cGVkZWYgSW52b2thYmxlPFJfLCBBMSwgQTIsIEEzPiBTdXBlcmNsYXNzOwoKICAgICAgICB0eXBlZGVmIHR5cGVuYW1lIE1lbWJlckZ1bmM8VE9iaiwgQ29uc3RuZXNzLCBSXywgQTEsIEEyLCBBMz46OnR5cGUgTWVtYmVyOwoKICAgICAgICB2aXJ0dWFsIFJfIG9wZXJhdG9yKCkoQTEgYTEsIEEyIGEyLCBBMyBhMykgeyAobV9vYmouKm1fbWVtYmVyKShhMSwgYTIsIGEzKTsgfQoKICAgICAgICBNZW1iZXJGdW5jdGlvbihUT2JqJiBvYmosIE1lbWJlciBtZW1iZXIpIDogbV9vYmoob2JqKSwgbV9tZW1iZXIobWVtYmVyKSB7fQoKICAgICAgICBib29sIGlzRXF1YWwoQ2xhc3N0eXBlIGNvbnN0JiBvdGhlciljb25zdHsKICAgICAgICAgICAgcmV0dXJuICgmbV9vYmogPT0gJihvdGhlci5tX29iaikpICYmIChtX21lbWJlciA9PSBvdGhlci5tX21lbWJlcik7CiAgICAgICAgfQoKICAgIHByaXZhdGU6CiAgICAgICAgVE9iaiYgbV9vYmo7CiAgICAgICAgTWVtYmVyIG1fbWVtYmVyOwogICAgfTsKCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaiwgdHlwZW5hbWUgQ29uc3RuZXNzLCB0eXBlbmFtZSBBMSwgdHlwZW5hbWUgQTI+CiAgICBzdHJ1Y3QgTWVtYmVyRnVuY3Rpb248VE9iaiwgQ29uc3RuZXNzLCBBMSwgQTI+IDogcHVibGljIEludm9rYWJsZTxSXywgQTEsIEEyPiB7CgogICAgICAgIHR5cGVkZWYgTWVtYmVyRnVuY3Rpb248VE9iaiwgQ29uc3RuZXNzLCBBMSwgQTI+IENsYXNzdHlwZTsKICAgICAgICB0eXBlZGVmIEludm9rYWJsZTxSXywgQTEsIEEyPiBTdXBlcmNsYXNzOwoKICAgICAgICB0eXBlZGVmIHR5cGVuYW1lIE1lbWJlckZ1bmM8VE9iaiwgQ29uc3RuZXNzLCBSXywgQTEsIEEyPjo6dHlwZSBNZW1iZXI7CgogICAgICAgIHZpcnR1YWwgUl8gb3BlcmF0b3IoKShBMSBhMSwgQTIgYTIpIHsgKG1fb2JqLiptX21lbWJlcikoYTEsIGEyKTsgfQoKICAgICAgICBNZW1iZXJGdW5jdGlvbihUT2JqJiBvYmosIE1lbWJlciBtZW1iZXIpIDogbV9vYmoob2JqKSwgbV9tZW1iZXIobWVtYmVyKSB7fQoKICAgICAgICBib29sIGlzRXF1YWwoQ2xhc3N0eXBlIGNvbnN0JiBvdGhlciljb25zdHsKICAgICAgICAgICAgcmV0dXJuICgmbV9vYmogPT0gJihvdGhlci5tX29iaikpICYmIChtX21lbWJlciA9PSBvdGhlci5tX21lbWJlcik7CiAgICAgICAgfQoKICAgIHByaXZhdGU6CiAgICAgICAgVE9iaiYgbV9vYmo7CiAgICAgICAgTWVtYmVyIG1fbWVtYmVyOwogICAgfTsKCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaiwgdHlwZW5hbWUgQ29uc3RuZXNzLCB0eXBlbmFtZSBBMT4KICAgIHN0cnVjdCBNZW1iZXJGdW5jdGlvbjxUT2JqLCBDb25zdG5lc3MsIEExPiA6IHB1YmxpYyBJbnZva2FibGU8Ul8sIEExPiB7CgogICAgICAgIHR5cGVkZWYgTWVtYmVyRnVuY3Rpb248VE9iaiwgQ29uc3RuZXNzLCBBMT4gQ2xhc3N0eXBlOwogICAgICAgIHR5cGVkZWYgSW52b2thYmxlPFJfLCBBMT4gU3VwZXJjbGFzczsKCiAgICAgICAgdHlwZWRlZiB0eXBlbmFtZSBNZW1iZXJGdW5jPFRPYmosIENvbnN0bmVzcywgUl8sIEExPjo6dHlwZSBNZW1iZXI7CgogICAgICAgIHZpcnR1YWwgUl8gb3BlcmF0b3IoKShBMSBhMSkgeyAobV9vYmouKm1fbWVtYmVyKShhMSk7IH0KCiAgICAgICAgTWVtYmVyRnVuY3Rpb24oVE9iaiYgb2JqLCBNZW1iZXIgbWVtYmVyKSA6IG1fb2JqKG9iaiksIG1fbWVtYmVyKG1lbWJlcikge30KCiAgICAgICAgYm9vbCBpc0VxdWFsKENsYXNzdHlwZSBjb25zdCYgb3RoZXIpY29uc3R7CiAgICAgICAgICAgIHJldHVybiAoJm1fb2JqID09ICYob3RoZXIubV9vYmopKSAmJiAobV9tZW1iZXIgPT0gb3RoZXIubV9tZW1iZXIpOwogICAgICAgIH0KCiAgICBwcml2YXRlOgogICAgICAgIFRPYmomIG1fb2JqOwogICAgICAgIE1lbWJlciBtX21lbWJlcjsKICAgIH07CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmosIHR5cGVuYW1lIENvbnN0bmVzcz4KICAgIHN0cnVjdCBNZW1iZXJGdW5jdGlvbjxUT2JqLCBDb25zdG5lc3M+IDogcHVibGljIEludm9rYWJsZTxSXz4gewoKICAgICAgICB0eXBlZGVmIE1lbWJlckZ1bmN0aW9uPFRPYmosIENvbnN0bmVzcz4gQ2xhc3N0eXBlOwogICAgICAgIHR5cGVkZWYgSW52b2thYmxlPFJfPiBTdXBlcmNsYXNzOwoKICAgICAgICB0eXBlZGVmIHR5cGVuYW1lIE1lbWJlckZ1bmM8VE9iaiwgQ29uc3RuZXNzLCBSXz46OnR5cGUgTWVtYmVyOwoKICAgICAgICB2aXJ0dWFsIFJfIG9wZXJhdG9yKCkoKSB7IChtX29iai4qbV9tZW1iZXIpKCk7IH0KCiAgICAgICAgTWVtYmVyRnVuY3Rpb24oVE9iaiYgb2JqLCBNZW1iZXIgbWVtYmVyKSA6IG1fb2JqKG9iaiksIG1fbWVtYmVyKG1lbWJlcikge30KCiAgICAgICAgYm9vbCBpc0VxdWFsKENsYXNzdHlwZSBjb25zdCYgb3RoZXIpY29uc3R7CiAgICAgICAgICAgIHJldHVybiAoJm1fb2JqID09ICYob3RoZXIubV9vYmopKSAmJiAobV9tZW1iZXIgPT0gb3RoZXIubV9tZW1iZXIpOwogICAgICAgIH0KCiAgICBwcml2YXRlOgogICAgICAgIFRPYmomIG1fb2JqOwogICAgICAgIE1lbWJlciBtX21lbWJlcjsKICAgIH07CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIEExID0gdm9pZCwgdHlwZW5hbWUgQTIgPSB2b2lkLCB0eXBlbmFtZSBBMyA9IHZvaWQsIHR5cGVuYW1lIEE0ID0gdm9pZCwgdHlwZW5hbWUgQTUgPSB2b2lkLCB0eXBlbmFtZSBpc0RlZmF1bHQgPSBEZWZhdWx0PgogICAgc3RydWN0IEJvdW5kRnVuY3Rpb247CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIEExLCB0eXBlbmFtZSBBMiwgdHlwZW5hbWUgQTMsIHR5cGVuYW1lIEE0PgogICAgc3RydWN0IEJvdW5kRnVuY3Rpb248QTEsIEEyLCBBMywgQTQ+IHsKICAgICAgICBBMSBhMTsKICAgICAgICBBMiBhMjsKICAgICAgICBBMyBhMzsKICAgICAgICBBNCBhNDsKICAgICAgICBCb3VuZEZ1bmN0aW9uKEExIGExXywgQTIgYTJfLCBBMyBhM18sIEE0IGE0Xyk6YTEoYTFfKSxhMihhMl8pLGEzKGEzXyksYTQoYTRfKXt9CiAgICAgICAgdmlydHVhbCBSXyBvcGVyYXRvcigpKEludm9rYWJsZTxSXyxBMSwgQTIsIEEzLCBBND4mIGludm9rYWJsZSkgeyBpbnZva2FibGUoYTEsYTIsYTMsYTQpOyB9CiAgICB9OwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBBMSwgdHlwZW5hbWUgQTIsIHR5cGVuYW1lIEEzPgogICAgc3RydWN0IEJvdW5kRnVuY3Rpb248QTEsIEEyLCBBMz4gewogICAgICAgIEExIGExOwogICAgICAgIEEyIGEyOwogICAgICAgIEEzIGEzOwogICAgICAgIEJvdW5kRnVuY3Rpb24oQTEgYTFfLCBBMiBhMl8sIEEzIGEzXyk6YTEoYTFfKSxhMihhMl8pLGEzKGEzXyl7fQogICAgICAgIHZpcnR1YWwgUl8gb3BlcmF0b3IoKShJbnZva2FibGU8Ul8sQTEsIEEyLCBBMz4mIGludm9rYWJsZSkgeyBpbnZva2FibGUoYTEsYTIsYTMpOyB9CiAgICB9OwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBBMSwgdHlwZW5hbWUgQTI+CiAgICBzdHJ1Y3QgQm91bmRGdW5jdGlvbjxBMSwgQTI+IHsKICAgICAgICBBMSBhMTsKICAgICAgICBBMiBhMjsKICAgICAgICBCb3VuZEZ1bmN0aW9uKEExIGExXywgQTIgYTJfKTphMShhMV8pLGEyKGEyXyl7fQogICAgICAgIHZpcnR1YWwgUl8gb3BlcmF0b3IoKShJbnZva2FibGU8Ul8sQTEsIEEyPiYgaW52b2thYmxlKSB7IGludm9rYWJsZShhMSxhMik7IH0KICAgIH07CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIEExPgogICAgc3RydWN0IEJvdW5kRnVuY3Rpb248QTE+IHsKICAgICAgICBBMSBhMTsKICAgICAgICBCb3VuZEZ1bmN0aW9uKEExIGExXyk6YTEoYTFfKXt9CiAgICAgICAgdmlydHVhbCBSXyBvcGVyYXRvcigpKEludm9rYWJsZTxSXyxBMT4mIGludm9rYWJsZSkgeyBpbnZva2FibGUoYTEpOyB9CiAgICB9OwoKICAgIHRlbXBsYXRlPHR5cGVuYW1lIGlzRGVmYXVsdD4gIC8vIG11c3QgaGF2ZSBhdCBsZWFzdCBvbmUgdGVtcGxhdGUgcGFyYW1ldGVyIHRvIGNvbXBpbGUhCiAgICBzdHJ1Y3QgQm91bmRGdW5jdGlvbjx2b2lkLHZvaWQsdm9pZCx2b2lkLHZvaWQsaXNEZWZhdWx0PiB7CiAgICAgICAgQm91bmRGdW5jdGlvbigpe30KICAgICAgICB2aXJ0dWFsIFJfIG9wZXJhdG9yKCkoSW52b2thYmxlPFJfPiYgaW52b2thYmxlKSB7IGludm9rYWJsZSgpOyB9CiAgICB9Owp9OwoKc3RydWN0IFNjb3BlZEludmVyc2lvbnsKICAgIGJvb2wmIHRhcmdldDsKICAgIGNvbnN0IGJvb2wgb3JpZ1ZhbHVlOwogICAgU2NvcGVkSW52ZXJzaW9uKGJvb2wmIHRhcmdldF8pOnRhcmdldCh0YXJnZXRfKSxvcmlnVmFsdWUodGFyZ2V0Xyl7dGFyZ2V0ID0gIXRhcmdldDt9CiAgICB+U2NvcGVkSW52ZXJzaW9uKCl7dGFyZ2V0ID0gb3JpZ1ZhbHVlO30KfTsKCgoKdHlwZWRlZiBib29sIERpc2Nvbm5lY3Rpb25QZW5kaW5nOwppbmxpbmUgRGlzY29ubmVjdGlvblBlbmRpbmcgZGlzY29ubmVjdFBlbmRpbmcoKXtyZXR1cm4gdHJ1ZTt9CmlubGluZSBEaXNjb25uZWN0aW9uUGVuZGluZyBjb25uZWN0ZWQoKXtyZXR1cm4gZGlzY29ubmVjdFBlbmRpbmcoKT09ZmFsc2U7fQoKCnRlbXBsYXRlPHR5cGVuYW1lIFRJbnZva2FibGVQdHI+CnN0cnVjdCBJc1BlbmRpbmdEaXNjb25uZWN0IHsKCiAgICB0eXBlZGVmIHN0ZDo6cGFpcjxUSW52b2thYmxlUHRyLGJvb2w+IFNsb3Q7CgogICAgYm9vbCBvcGVyYXRvcigpKFNsb3QgY29uc3QmIG90aGVyKWNvbnN0ewogICAgICAgIHJldHVybiBvdGhlci5zZWNvbmQgPT0gZGlzY29ubmVjdFBlbmRpbmcoKTsKICAgIH0KfTsKCgovKioKICogQGJyaWVmIENvbXBhcmluZyBvZiAyIGludm9rYWJsZSBpbnN0YW5jZXMKICovCnRlbXBsYXRlPHR5cGVuYW1lIFRJbnZva2FibGU+CnN0cnVjdCBJc0NhbGxlciB7CgogICAgdHlwZWRlZiBzdGQ6OnBhaXI8dHlwZW5hbWUgVEludm9rYWJsZTo6U3VwZXJjbGFzcyosYm9vbD4gU2xvdDsKCiAgICBJc0NhbGxlcihUSW52b2thYmxlIGNvbnN0JiBjKTppbnZva2FibGUoYyl7fQogICAgVEludm9rYWJsZSBjb25zdCYgaW52b2thYmxlOwoKICAgIGJvb2wgb3BlcmF0b3IoKShTbG90IGNvbnN0JiBvdGhlciljb25zdHsKICAgICAgICBUSW52b2thYmxlIGNvbnN0KiB0ID0gZHluYW1pY19jYXN0PFRJbnZva2FibGUgY29uc3QqPihvdGhlci5maXJzdCk7CiAgICAgICAgcmV0dXJuIHQhPU5VTEwgPyBpbnZva2FibGUuaXNFcXVhbCgqdCkgOiBmYWxzZTsKICAgIH0KfTsKCgoKCi8qKgogKiBSZW1vdmluZyBhIHNsb3QgZnJvbSB0aGUgbGlzdCBvZiBzbG90cwogKi8KdGVtcGxhdGU8dHlwZW5hbWUgU2xvdHM+CnZvaWQgZGlzY29ubmVjdE5vdyhTbG90cyYgc2xvdHMpewoKICAgIGNvbnN0IElzUGVuZGluZ0Rpc2Nvbm5lY3Q8dHlwZW5hbWUgU2xvdHM6OnZhbHVlX3R5cGU6OmZpcnN0X3R5cGU+IHByZWQ7CgogICAgdHlwZWRlZiB0eXBlbmFtZSBTbG90czo6Y29uc3RfaXRlcmF0b3IgSXQ7CiAgICBmb3IoSXQgaXQgPSBzbG90cy5iZWdpbigpLCBlbmQgPSBzbG90cy5lbmQoKTtpdCE9ZW5kOysraXQpCiAgICAgICAgaWYgKHByZWQoKml0KSkKICAgICAgICAgICAgZGVsZXRlIGl0LT5maXJzdDsKCiAgICBzbG90cy5lcmFzZShzdGQ6OnJlbW92ZV9pZihzbG90cy5iZWdpbigpLHNsb3RzLmVuZCgpLCBwcmVkKSwgc2xvdHMuZW5kKCkpOwp9Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBTbG90cywgdHlwZW5hbWUgVENhbGxlcj4Kdm9pZCBkaXNjb25uZWN0RGVsYXllZChTbG90cyYgc2xvdHMsIFRDYWxsZXIgY29uc3QmIGNhbGxlcil7CgogICAgY29uc3QgSXNDYWxsZXI8VENhbGxlcj4gcHJlZChjYWxsZXIpOwoKICAgIHR5cGVkZWYgdHlwZW5hbWUgU2xvdHM6Oml0ZXJhdG9yIEl0OwogICAgZm9yKEl0IGl0ID0gc2xvdHMuYmVnaW4oKSwgZW5kID0gc2xvdHMuZW5kKCk7aXQhPWVuZDsrK2l0KQogICAgICAgIGlmIChwcmVkKCppdCkpCiAgICAgICAgICAgIGl0LT5zZWNvbmQgPSBkaXNjb25uZWN0UGVuZGluZygpOwoKfQoKCnRlbXBsYXRlPHR5cGVuYW1lIFNsb3RzLCB0eXBlbmFtZSBUQ2FsbGVyPgp2b2lkIGRpc2Nvbm5lY3QoU2xvdHMmIHNsb3RzLCBib29sIGlzQ3VycmVudGx5RW1pdHRpbmcsIFRDYWxsZXIgY29uc3QmIGNhbGxlcil7CgogICAgZGlzY29ubmVjdERlbGF5ZWQoc2xvdHMsY2FsbGVyKTsKCiAgICBpZiAoIWlzQ3VycmVudGx5RW1pdHRpbmcpCiAgICAgICAgZGlzY29ubmVjdE5vdyhzbG90cyk7Cn0KCi8qKgogKiBSZW1vdmluZyBhIHNsb3QgZnJvbSB0aGUgbGlzdCBvZiBzbG90cwogKi8KCgp0ZW1wbGF0ZTx0eXBlbmFtZSBTbG90cz4Kdm9pZCBkaXNjb25uZWN0QWxsKFNsb3RzJiBzbG90cyl7CiAgICB0eXBlZGVmIHR5cGVuYW1lIFNsb3RzOjpjb25zdF9pdGVyYXRvciBTbG90c0NJdDsKICAgIGZvciAoU2xvdHNDSXQgaXQgPSBzbG90cy5iZWdpbigpLCBlbmQgPSBzbG90cy5lbmQoKTsgaXQgIT0gZW5kOyArK2l0KQogICAgICAgIGRlbGV0ZSAqaXQ7CiAgICBzbG90cy5jbGVhcigpOwp9Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBTbG90cz4Kdm9pZCBkaXNjb25uZWN0QWxsTm93KFNsb3RzJiBzbG90cyl7CiAgICB0eXBlZGVmIHR5cGVuYW1lIFNsb3RzOjpjb25zdF9pdGVyYXRvciBTbG90c0NJdDsKICAgIGZvciAoU2xvdHNDSXQgaXQgPSBzbG90cy5iZWdpbigpLCBlbmQgPSBzbG90cy5lbmQoKTsgaXQgIT0gZW5kOyArK2l0KQogICAgICAgIGRlbGV0ZSBpdC0+Zmlyc3Q7CiAgICBzbG90cy5jbGVhcigpOwp9Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBTbG90cz4Kdm9pZCBkaXNjb25uZWN0QWxsRGVsYXllZChTbG90cyYgc2xvdHMpewogICAgdHlwZWRlZiB0eXBlbmFtZSBTbG90czo6aXRlcmF0b3IgU2xvdHNDSXQ7CiAgICBmb3IgKFNsb3RzQ0l0IGl0ID0gc2xvdHMuYmVnaW4oKSwgZW5kID0gc2xvdHMuZW5kKCk7IGl0ICE9IGVuZDsgKytpdCkKICAgICAgICBpdC0+c2Vjb25kID0gZGlzY29ubmVjdFBlbmRpbmcoKTsKCn0KCnRlbXBsYXRlPHR5cGVuYW1lIFNsb3RzPgp2b2lkIGRpc2Nvbm5lY3RBbGwoU2xvdHMmIHNsb3RzLCBib29sIGlzQ3VycmVudGx5RW1pdHRpbmcpewogICAgaWYgKGlzQ3VycmVudGx5RW1pdHRpbmcpCiAgICAgICAgZGlzY29ubmVjdEFsbERlbGF5ZWQoc2xvdHMpOwogICAgZWxzZQogICAgICAgIGRpc2Nvbm5lY3RBbGxOb3coc2xvdHMpOwoKfQoKdGVtcGxhdGU8dHlwZW5hbWUgT3V0VHlwZV8sIHR5cGVuYW1lIENhbGxSZXN1bHQ+CnZvaWQgYWdncmVnYXRlUmV0dXJuVmFsdWUoT3V0VHlwZV8mIGMsIENhbGxSZXN1bHQgY29uc3QmIHIpIHsKICAgIGMub3V0LnB1c2hfYmFjayhyKTsKfQoKdGVtcGxhdGUgPHR5cGVuYW1lIFI+CnN0cnVjdCBSZXR1cm5WYWx1ZUFnZ3JlZ2F0b3IgewoKICAgIHR5cGVkZWYgUiBSXzsKCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgU2xvdHMsIHR5cGVuYW1lIEFyZ3M+CiAgICBzdGF0aWMgdm9pZCBpbnZva2VBbmRBZ2dyZWdhdGUoUmV0dXJuVmFsdWVBZ2dyZWdhdGU8Ul8+JiByLCBTbG90cyYgc2xvdHMsIEFyZ3MmIGFyZ3MpIHsKCiAgICAgICAgdHlwZWRlZiB0eXBlbmFtZSBTbG90czo6Y29uc3RfaXRlcmF0b3IgU2xvdHNDSXQ7CiAgICAgICAgZm9yIChTbG90c0NJdCBpdCA9IHNsb3RzLmJlZ2luKCksIGVuZCA9IHNsb3RzLmVuZCgpOyBpdCAhPSBlbmQ7ICsraXQpIHsKICAgICAgICAgICAgIGFnZ3JlZ2F0ZVJldHVyblZhbHVlKHIsYXJncygqKGl0LT5maXJzdCkpKTsKICAgICAgICB9CiAgICB9Cn07Cgp0ZW1wbGF0ZSA8PgpzdHJ1Y3QgUmV0dXJuVmFsdWVBZ2dyZWdhdG9yPHZvaWQ+IHsKCiAgICB0eXBlZGVmIHZvaWQgUl87CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFNsb3RzLCB0eXBlbmFtZSBBcmdzPgogICAgc3RhdGljIHZvaWQgaW52b2tlQW5kQWdncmVnYXRlKFJldHVyblZhbHVlQWdncmVnYXRlPFJfPiYsIFNsb3RzJiBzbG90cywgQXJncyYgYXJncykgewoKICAgICAgICB0eXBlZGVmIHR5cGVuYW1lIFNsb3RzOjpjb25zdF9pdGVyYXRvciBTbG90c0NJdDsKICAgICAgICBmb3IgKFNsb3RzQ0l0IGl0ID0gc2xvdHMuYmVnaW4oKSwgZW5kID0gc2xvdHMuZW5kKCk7IGl0ICE9IGVuZDsgKytpdCkgewogICAgICAgICAgICAgYXJncygqKGl0LT5maXJzdCkpOwogICAgICAgIH0KICAgIH0KfTsKCgp0ZW1wbGF0ZTx0eXBlbmFtZSBTbG90cywgdHlwZW5hbWUgSW52b2thYmxlPgp2b2lkIGNvbm5lY3QoU2xvdHMmIHNsb3RzLCBJbnZva2FibGUgaW52b2thYmxlKXsKICAgIHNsb3RzLnB1c2hfYmFjayhpbnZva2FibGUpOwp9CgoKdGVtcGxhdGU8dHlwZW5hbWUgU2xvdHM+CnZvaWQgY29ubmVjdFBlbmRpbmcoU2xvdHMmIHNsb3RzLCBTbG90cyYgcGVuZGluZ0Nvbm5lY3RzKXsKCiAgICB0eXBlZGVmIHR5cGVuYW1lIFNsb3RzOjpjb25zdF9pdGVyYXRvciBTbG90c0NJdDsKICAgIGZvciAoU2xvdHNDSXQgaXQgPSBwZW5kaW5nQ29ubmVjdHMuYmVnaW4oKSwgZW5kID0gcGVuZGluZ0Nvbm5lY3RzLmVuZCgpOyBpdCAhPSBlbmQ7ICsraXQpCiAgICAgICAgIGNvbm5lY3Qoc2xvdHMsKml0KTsKCiAgICBwZW5kaW5nQ29ubmVjdHMuY2xlYXIoKTsKfQoKdGVtcGxhdGU8dHlwZW5hbWUgU2xvdHM+CnZvaWQgZGlzY29ubmVjdFBlbmRpbmcoU2xvdHMmIHNsb3RzKXsKICAgIGRpc2Nvbm5lY3ROb3coc2xvdHMpOwp9CgoKfSAvL25hbWVzcGFjZSBkZXRhaWwKCgovKioKICogQGJyaWVmIE1haW4gY2xhc3MgcmVhbGl6aW5nIHNpZ25hbCBzbG90IGJlaGF2aW91ci4KICovCnRlbXBsYXRlIDx0eXBlbmFtZSBURnVuYz4Kc3RydWN0IFNpZ25hbDsKCnRlbXBsYXRlIDx0eXBlbmFtZSBSLCB0eXBlbmFtZSBBMSwgdHlwZW5hbWUgQTIsIHR5cGVuYW1lIEEzLHR5cGVuYW1lIEE0PgpzdHJ1Y3QgU2lnbmFsPFIoQTEsIEEyLCBBMywgQTQpPiB7CgogICAgdm9pZCBjb25uZWN0KFIgKCptZW1iZXIpKEExLCBBMiwgQTMsIEE0KSkgewogICAgICAgIFNjb3BlZExvY2tfIGxvY2soc2xvdHNNdXRleCk7CiAgICAgICAgZGV0YWlsOjpjb25uZWN0KGlzQ3VycmVudGx5RW1pdHRpbmcgPyBwZW5kaW5nQ29ubmVjdHMgOiBzbG90cywgU2xvdChuZXcgR0NhbGxlcihtZW1iZXIpLGRldGFpbDo6Y29ubmVjdGVkKCkpKTsKICAgIH0KCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaj4KICAgIHZvaWQgY29ubmVjdChUT2JqJiBvYmosIFIgKFRPYmo6OiptZW1iZXIpKEExLCBBMiwgQTMsIEE0KSkgewogICAgICAgIFNjb3BlZExvY2tfIGxvY2soc2xvdHNNdXRleCk7CiAgICAgICAgdHlwZWRlZiB0eXBlbmFtZSBNQ2FsbGVyPFRPYmosZGV0YWlsOjpOb25Db25zdD46OnR5cGUgTUNhbGxlcl87CiAgICAgICAgZGV0YWlsOjpjb25uZWN0KGlzQ3VycmVudGx5RW1pdHRpbmcgPyBwZW5kaW5nQ29ubmVjdHMgOiBzbG90cywgU2xvdChuZXcgTUNhbGxlcl8ob2JqLCBtZW1iZXIpLGRldGFpbDo6Y29ubmVjdGVkKCkpKTsKICAgIH0KCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaj4KICAgIHZvaWQgY29ubmVjdChUT2JqIGNvbnN0JiBvYmosIFIgKFRPYmo6OiptZW1iZXIpKEExLCBBMiwgQTMsIEE0KSBjb25zdCkgewogICAgICAgIFNjb3BlZExvY2tfIGxvY2soc2xvdHNNdXRleCk7CiAgICAgICAgdHlwZWRlZiB0eXBlbmFtZSBNQ2FsbGVyPGNvbnN0IFRPYmosZGV0YWlsOjpDb25zdD46OnR5cGUgTUNhbGxlcl87CiAgICAgICAgZGV0YWlsOjpjb25uZWN0KGlzQ3VycmVudGx5RW1pdHRpbmcgPyBwZW5kaW5nQ29ubmVjdHMgOiBzbG90cywgU2xvdChuZXcgTUNhbGxlcl8ob2JqLCBtZW1iZXIpLGRldGFpbDo6Y29ubmVjdGVkKCkpKTsKICAgIH0KCiAgICBkZXRhaWw6OlJldHVyblZhbHVlQWdncmVnYXRlPFI+IGVtaXQoQTEgYTEsIEEyIGEyLCBBMyBhMywgQTQgYTQpIHsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIEFyZ3MgYXJncyhhMSxhMixhMyxhNCk7CiAgICAgICAgZGV0YWlsOjpSZXR1cm5WYWx1ZUFnZ3JlZ2F0ZTxSPiByOwogICAgICAgIGlmIChpc0N1cnJlbnRseUVtaXR0aW5nKSByZXR1cm4gcjsKICAgICAgICBkZXRhaWw6OlNjb3BlZEludmVyc2lvbiBpbnZlcnRlcihpc0N1cnJlbnRseUVtaXR0aW5nKTsKICAgICAgICBkZXRhaWw6OlJldHVyblZhbHVlQWdncmVnYXRvcjxSPjo6aW52b2tlQW5kQWdncmVnYXRlKHIsIHNsb3RzLCBhcmdzKTsKICAgICAgICBkZXRhaWw6OmRpc2Nvbm5lY3RQZW5kaW5nKHNsb3RzKTsKICAgICAgICBkZXRhaWw6OmNvbm5lY3RQZW5kaW5nKHNsb3RzLCBwZW5kaW5nQ29ubmVjdHMpOwogICAgICAgIHJldHVybiByOwogICAgfQoKICAgIHZvaWQgZGlzY29ubmVjdChSICgqbWVtYmVyKShBMSwgQTIsIEEzLCBBNCkpIHsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIGRldGFpbDo6ZGlzY29ubmVjdChzbG90cywgaXNDdXJyZW50bHlFbWl0dGluZywgR0NhbGxlcihtZW1iZXIpKTsKICAgIH0KCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaj4KICAgIHZvaWQgZGlzY29ubmVjdChUT2JqJiBvYmosIFIgKFRPYmo6OiptZW1iZXIpKEExLCBBMiwgQTMsIEE0KSkgewogICAgICAgIFNjb3BlZExvY2tfIGxvY2soc2xvdHNNdXRleCk7CiAgICAgICAgdHlwZWRlZiB0eXBlbmFtZSBNQ2FsbGVyPFRPYmosZGV0YWlsOjpOb25Db25zdD46OnR5cGUgTUNhbGxlcl87CiAgICAgICAgZGV0YWlsOjpkaXNjb25uZWN0KHNsb3RzLCBpc0N1cnJlbnRseUVtaXR0aW5nLCBNQ2FsbGVyXyhvYmosbWVtYmVyKSk7CiAgICB9CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmo+CiAgICB2b2lkIGRpc2Nvbm5lY3QoVE9iaiBjb25zdCYgb2JqLCBSIChUT2JqOjoqbWVtYmVyKShBMSwgQTIsIEEzLCBBNCkgY29uc3QpIHsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIHR5cGVkZWYgdHlwZW5hbWUgTUNhbGxlcjxjb25zdCBUT2JqLGRldGFpbDo6Q29uc3Q+Ojp0eXBlIE1DYWxsZXJfOwogICAgICAgIGRldGFpbDo6ZGlzY29ubmVjdChzbG90cywgaXNDdXJyZW50bHlFbWl0dGluZywgTUNhbGxlcl8ob2JqLG1lbWJlcikpOwogICAgfQoKICAgIHZvaWQgZGlzY29ubmVjdEFsbCgpewogICAgICAgIFNjb3BlZExvY2tfIGxvY2soc2xvdHNNdXRleCk7CiAgICAgICAgZGV0YWlsOjpkaXNjb25uZWN0QWxsKHNsb3RzLCBpc0N1cnJlbnRseUVtaXR0aW5nKTsKICAgIH0KCiAgICB+U2lnbmFsKCl7IGFzc2VydChpc0N1cnJlbnRseUVtaXR0aW5nPT1mYWxzZSk7IGRpc2Nvbm5lY3RBbGwoKTsgfSAvL3Vwb24gcmV0dXJuaW5nIGZyb20gZHRvciBvYmplY3QgaXMgaW52YWxpZCBzbyBhIHBlbmRpbmcgZW1pdCgpLWNhbGwgd291bGQgYmUgaW52YWxpZCB0b28hCgogICBwcml2YXRlOgogICAgdHlwZWRlZiB0eXBlbmFtZSBkZXRhaWw6Okludm9rYWJsZUltcGw8Uj46OnRlbXBsYXRlIEJvdW5kRnVuY3Rpb248QTEsIEEyLCBBMywgQTQ+IEFyZ3M7CiAgICB0eXBlZGVmIHR5cGVuYW1lIGRldGFpbDo6SW52b2thYmxlSW1wbDxSPjo6dGVtcGxhdGUgR2xvYmFsRnVuY3Rpb248QTEsIEEyLCBBMywgQTQ+IEdDYWxsZXI7CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmosIHR5cGVuYW1lIENvbnN0bmVzcz4KICAgIHN0cnVjdCBNQ2FsbGVyeyB0eXBlZGVmIHR5cGVuYW1lIGRldGFpbDo6SW52b2thYmxlSW1wbDxSPjo6dGVtcGxhdGUgTWVtYmVyRnVuY3Rpb248VE9iaiwgQ29uc3RuZXNzLCBBMSwgQTIsIEEzLCBBND4gdHlwZTsgfTsKCiAgICB0eXBlZGVmIHN0ZDo6cGFpcjxkZXRhaWw6Okludm9rYWJsZTxSLCBBMSwgQTIsIEEzLCBBND4qLGRldGFpbDo6RGlzY29ubmVjdGlvblBlbmRpbmc+IFNsb3Q7CiAgICB0eXBlZGVmIHR5cGVuYW1lIGRldGFpbDo6U2xvdENvbnRhaW5lcjxTbG90Pjo6dHlwZSBTbG90czsKCiAgICB0eXBlZGVmIGRldGFpbDo6TXV0ZXg6OnR5cGUgTXV0ZXhfOwogICAgdHlwZWRlZiBkZXRhaWw6OlNjb3BlZExvY2s6OnR5cGUgU2NvcGVkTG9ja187CgogICAgYm9vbCBpc0N1cnJlbnRseUVtaXR0aW5nID0gZmFsc2U7CiAgICBTbG90cyBwZW5kaW5nQ29ubmVjdHM7CiAgICBTbG90cyBzbG90czsKICAgIE11dGV4XyBzbG90c011dGV4Owp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lIFIsIHR5cGVuYW1lIEExLCB0eXBlbmFtZSBBMiwgdHlwZW5hbWUgQTM+CnN0cnVjdCBTaWduYWw8UihBMSwgQTIsIEEzKT4gewoKICAgIHZvaWQgY29ubmVjdChSICgqbWVtYmVyKShBMSwgQTIsIEEzKSkgewogICAgICAgIFNjb3BlZExvY2tfIGxvY2soc2xvdHNNdXRleCk7CiAgICAgICAgZGV0YWlsOjpjb25uZWN0KGlzQ3VycmVudGx5RW1pdHRpbmcgPyBwZW5kaW5nQ29ubmVjdHMgOiBzbG90cywgU2xvdChuZXcgR0NhbGxlcihtZW1iZXIpLGRldGFpbDo6Y29ubmVjdGVkKCkpKTsKICAgIH0KCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaj4KICAgIHZvaWQgY29ubmVjdChUT2JqJiBvYmosIFIgKFRPYmo6OiptZW1iZXIpKEExLCBBMiwgQTMpKSB7CiAgICAgICAgU2NvcGVkTG9ja18gbG9jayhzbG90c011dGV4KTsKICAgICAgICB0eXBlZGVmIHR5cGVuYW1lIE1DYWxsZXI8VE9iaixkZXRhaWw6Ok5vbkNvbnN0Pjo6dHlwZSBNQ2FsbGVyXzsKICAgICAgICBkZXRhaWw6OmNvbm5lY3QoaXNDdXJyZW50bHlFbWl0dGluZyA/IHBlbmRpbmdDb25uZWN0cyA6IHNsb3RzLCBTbG90KG5ldyBNQ2FsbGVyXyhvYmosIG1lbWJlciksZGV0YWlsOjpjb25uZWN0ZWQoKSkpOwogICAgfQoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUT2JqPgogICAgdm9pZCBjb25uZWN0KFRPYmogY29uc3QmIG9iaiwgUiAoVE9iajo6Km1lbWJlcikoQTEsIEEyLCBBMykgY29uc3QpIHsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIHR5cGVkZWYgdHlwZW5hbWUgTUNhbGxlcjxjb25zdCBUT2JqLGRldGFpbDo6Q29uc3Q+Ojp0eXBlIE1DYWxsZXJfOwogICAgICAgIGRldGFpbDo6Y29ubmVjdChpc0N1cnJlbnRseUVtaXR0aW5nID8gcGVuZGluZ0Nvbm5lY3RzIDogc2xvdHMsIFNsb3QobmV3IE1DYWxsZXJfKG9iaiwgbWVtYmVyKSxkZXRhaWw6OmNvbm5lY3RlZCgpKSk7CiAgICB9CgogICAgZGV0YWlsOjpSZXR1cm5WYWx1ZUFnZ3JlZ2F0ZTxSPiBlbWl0KEExIGExLCBBMiBhMiwgQTMgYTMpIHsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIEFyZ3MgYXJncyhhMSxhMixhMyk7CiAgICAgICAgZGV0YWlsOjpSZXR1cm5WYWx1ZUFnZ3JlZ2F0ZTxSPiByOwogICAgICAgIGlmIChpc0N1cnJlbnRseUVtaXR0aW5nKSByZXR1cm4gcjsKICAgICAgICBkZXRhaWw6OlNjb3BlZEludmVyc2lvbiBpbnZlcnRlcihpc0N1cnJlbnRseUVtaXR0aW5nKTsKICAgICAgICBkZXRhaWw6OlJldHVyblZhbHVlQWdncmVnYXRvcjxSPjo6aW52b2tlQW5kQWdncmVnYXRlKHIsIHNsb3RzLCBhcmdzKTsKICAgICAgICBkZXRhaWw6OmRpc2Nvbm5lY3RQZW5kaW5nKHNsb3RzKTsKICAgICAgICBkZXRhaWw6OmNvbm5lY3RQZW5kaW5nKHNsb3RzLCBwZW5kaW5nQ29ubmVjdHMpOwogICAgICAgIHJldHVybiByOwogICAgfQoKICAgIHZvaWQgZGlzY29ubmVjdChSICgqbWVtYmVyKShBMSwgQTIsIEEzKSkgewogICAgICAgIFNjb3BlZExvY2tfIGxvY2soc2xvdHNNdXRleCk7CiAgICAgICAgZGV0YWlsOjpkaXNjb25uZWN0KHNsb3RzLCBpc0N1cnJlbnRseUVtaXR0aW5nLCBHQ2FsbGVyKG1lbWJlcikpOwogICAgfQoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUT2JqPgogICAgdm9pZCBkaXNjb25uZWN0KFRPYmomIG9iaiwgUiAoVE9iajo6Km1lbWJlcikoQTEsIEEyLCBBMykpIHsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIHR5cGVkZWYgdHlwZW5hbWUgTUNhbGxlcjxUT2JqLGRldGFpbDo6Tm9uQ29uc3Q+Ojp0eXBlIE1DYWxsZXJfOwogICAgICAgIGRldGFpbDo6ZGlzY29ubmVjdChzbG90cywgaXNDdXJyZW50bHlFbWl0dGluZywgTUNhbGxlcl8ob2JqLG1lbWJlcikpOwogICAgfQoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUT2JqPgogICAgdm9pZCBkaXNjb25uZWN0KFRPYmogY29uc3QmIG9iaiwgUiAoVE9iajo6Km1lbWJlcikoQTEsIEEyLCBBMykgY29uc3QpIHsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIHR5cGVkZWYgdHlwZW5hbWUgTUNhbGxlcjxjb25zdCBUT2JqLGRldGFpbDo6Q29uc3Q+Ojp0eXBlIE1DYWxsZXJfOwogICAgICAgIGRldGFpbDo6ZGlzY29ubmVjdChzbG90cywgaXNDdXJyZW50bHlFbWl0dGluZywgTUNhbGxlcl8ob2JqLG1lbWJlcikpOwogICAgfQoKICAgIHZvaWQgZGlzY29ubmVjdEFsbCgpewogICAgICAgIFNjb3BlZExvY2tfIGxvY2soc2xvdHNNdXRleCk7CiAgICAgICAgZGV0YWlsOjpkaXNjb25uZWN0QWxsKHNsb3RzLCBpc0N1cnJlbnRseUVtaXR0aW5nKTsKICAgIH0KCiAgICB+U2lnbmFsKCl7IGFzc2VydChpc0N1cnJlbnRseUVtaXR0aW5nPT1mYWxzZSk7IGRpc2Nvbm5lY3RBbGwoKTsgfSAvL3Vwb24gcmV0dXJuaW5nIGZyb20gZHRvciBvYmplY3QgaXMgaW52YWxpZCBzbyBhIHBlbmRpbmcgZW1pdCgpLWNhbGwgd291bGQgYmUgaW52YWxpZCB0b28hCgogICBwcml2YXRlOgogICAgdHlwZWRlZiB0eXBlbmFtZSBkZXRhaWw6Okludm9rYWJsZUltcGw8Uj46OnRlbXBsYXRlIEJvdW5kRnVuY3Rpb248QTEsIEEyLCBBMz4gQXJnczsKICAgIHR5cGVkZWYgdHlwZW5hbWUgZGV0YWlsOjpJbnZva2FibGVJbXBsPFI+Ojp0ZW1wbGF0ZSBHbG9iYWxGdW5jdGlvbjxBMSwgQTIsIEEzPiBHQ2FsbGVyOwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUT2JqLCB0eXBlbmFtZSBDb25zdG5lc3M+CiAgICBzdHJ1Y3QgTUNhbGxlcnsgdHlwZWRlZiB0eXBlbmFtZSBkZXRhaWw6Okludm9rYWJsZUltcGw8Uj46OnRlbXBsYXRlIE1lbWJlckZ1bmN0aW9uPFRPYmosIENvbnN0bmVzcywgQTEsIEEyLCBBMz4gdHlwZTsgfTsKCiAgICB0eXBlZGVmIHN0ZDo6cGFpcjxkZXRhaWw6Okludm9rYWJsZTxSLCBBMSwgQTIsIEEzPiosZGV0YWlsOjpEaXNjb25uZWN0aW9uUGVuZGluZz4gU2xvdDsKICAgIHR5cGVkZWYgdHlwZW5hbWUgZGV0YWlsOjpTbG90Q29udGFpbmVyPFNsb3Q+Ojp0eXBlIFNsb3RzOwoKICAgIHR5cGVkZWYgZGV0YWlsOjpNdXRleDo6dHlwZSBNdXRleF87CiAgICB0eXBlZGVmIGRldGFpbDo6U2NvcGVkTG9jazo6dHlwZSBTY29wZWRMb2NrXzsKCiAgICBib29sIGlzQ3VycmVudGx5RW1pdHRpbmcgPSBmYWxzZTsKICAgIFNsb3RzIHBlbmRpbmdDb25uZWN0czsKICAgIFNsb3RzIHNsb3RzOwogICAgTXV0ZXhfIHNsb3RzTXV0ZXg7Cn07CgoKCnRlbXBsYXRlIDx0eXBlbmFtZSBSLCB0eXBlbmFtZSBBMSwgdHlwZW5hbWUgQTI+CnN0cnVjdCBTaWduYWw8UihBMSwgQTIpPiB7CgogICAgdm9pZCBjb25uZWN0KFIgKCptZW1iZXIpKEExLCBBMikpIHsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIGRldGFpbDo6Y29ubmVjdChpc0N1cnJlbnRseUVtaXR0aW5nID8gcGVuZGluZ0Nvbm5lY3RzIDogc2xvdHMsIFNsb3QobmV3IEdDYWxsZXIobWVtYmVyKSxkZXRhaWw6OmNvbm5lY3RlZCgpKSk7CiAgICB9CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmo+CiAgICB2b2lkIGNvbm5lY3QoVE9iaiYgb2JqLCBSIChUT2JqOjoqbWVtYmVyKShBMSwgQTIpKSB7CiAgICAgICAgU2NvcGVkTG9ja18gbG9jayhzbG90c011dGV4KTsKICAgICAgICB0eXBlZGVmIHR5cGVuYW1lIE1DYWxsZXI8VE9iaixkZXRhaWw6Ok5vbkNvbnN0Pjo6dHlwZSBNQ2FsbGVyXzsKICAgICAgICBkZXRhaWw6OmNvbm5lY3QoaXNDdXJyZW50bHlFbWl0dGluZyA/IHBlbmRpbmdDb25uZWN0cyA6IHNsb3RzLCBTbG90KG5ldyBNQ2FsbGVyXyhvYmosIG1lbWJlciksZGV0YWlsOjpjb25uZWN0ZWQoKSkpOwogICAgfQoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUT2JqPgogICAgdm9pZCBjb25uZWN0KFRPYmogY29uc3QmIG9iaiwgUiAoVE9iajo6Km1lbWJlcikoQTEsIEEyKSBjb25zdCkgewogICAgICAgIFNjb3BlZExvY2tfIGxvY2soc2xvdHNNdXRleCk7CiAgICAgICAgdHlwZWRlZiB0eXBlbmFtZSBNQ2FsbGVyPGNvbnN0IFRPYmosZGV0YWlsOjpDb25zdD46OnR5cGUgTUNhbGxlcl87CiAgICAgICAgZGV0YWlsOjpjb25uZWN0KGlzQ3VycmVudGx5RW1pdHRpbmcgPyBwZW5kaW5nQ29ubmVjdHMgOiBzbG90cywgU2xvdChuZXcgTUNhbGxlcl8ob2JqLCBtZW1iZXIpLGRldGFpbDo6Y29ubmVjdGVkKCkpKTsKICAgIH0KCiAgICBkZXRhaWw6OlJldHVyblZhbHVlQWdncmVnYXRlPFI+IGVtaXQoQTEgYTEsIEEyIGEyKSB7CiAgICAgICAgU2NvcGVkTG9ja18gbG9jayhzbG90c011dGV4KTsKICAgICAgICBBcmdzIGFyZ3MoYTEsYTIpOwogICAgICAgIGRldGFpbDo6UmV0dXJuVmFsdWVBZ2dyZWdhdGU8Uj4gcjsKICAgICAgICBpZiAoaXNDdXJyZW50bHlFbWl0dGluZykgcmV0dXJuIHI7CiAgICAgICAgZGV0YWlsOjpTY29wZWRJbnZlcnNpb24gaW52ZXJ0ZXIoaXNDdXJyZW50bHlFbWl0dGluZyk7CiAgICAgICAgZGV0YWlsOjpSZXR1cm5WYWx1ZUFnZ3JlZ2F0b3I8Uj46Omludm9rZUFuZEFnZ3JlZ2F0ZShyLCBzbG90cywgYXJncyk7CiAgICAgICAgZGV0YWlsOjpkaXNjb25uZWN0UGVuZGluZyhzbG90cyk7CiAgICAgICAgZGV0YWlsOjpjb25uZWN0UGVuZGluZyhzbG90cywgcGVuZGluZ0Nvbm5lY3RzKTsKICAgICAgICByZXR1cm4gcjsKICAgIH0KCiAgICB2b2lkIGRpc2Nvbm5lY3QoUiAoKm1lbWJlcikoQTEsIEEyKSkgewogICAgICAgIFNjb3BlZExvY2tfIGxvY2soc2xvdHNNdXRleCk7CiAgICAgICAgZGV0YWlsOjpkaXNjb25uZWN0KHNsb3RzLCBpc0N1cnJlbnRseUVtaXR0aW5nLCBHQ2FsbGVyKG1lbWJlcikpOwogICAgfQoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUT2JqPgogICAgdm9pZCBkaXNjb25uZWN0KFRPYmomIG9iaiwgUiAoVE9iajo6Km1lbWJlcikoQTEsIEEyKSkgewogICAgICAgIFNjb3BlZExvY2tfIGxvY2soc2xvdHNNdXRleCk7CiAgICAgICAgdHlwZWRlZiB0eXBlbmFtZSBNQ2FsbGVyPFRPYmosZGV0YWlsOjpOb25Db25zdD46OnR5cGUgTUNhbGxlcl87CiAgICAgICAgZGV0YWlsOjpkaXNjb25uZWN0KHNsb3RzLCBpc0N1cnJlbnRseUVtaXR0aW5nLCBNQ2FsbGVyXyhvYmosbWVtYmVyKSk7CiAgICB9CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmo+CiAgICB2b2lkIGRpc2Nvbm5lY3QoVE9iaiBjb25zdCYgb2JqLCBSIChUT2JqOjoqbWVtYmVyKShBMSwgQTIpIGNvbnN0KSB7CiAgICAgICAgU2NvcGVkTG9ja18gbG9jayhzbG90c011dGV4KTsKICAgICAgICB0eXBlZGVmIHR5cGVuYW1lIE1DYWxsZXI8Y29uc3QgVE9iaixkZXRhaWw6OkNvbnN0Pjo6dHlwZSBNQ2FsbGVyXzsKICAgICAgICBkZXRhaWw6OmRpc2Nvbm5lY3Qoc2xvdHMsIGlzQ3VycmVudGx5RW1pdHRpbmcsIE1DYWxsZXJfKG9iaixtZW1iZXIpKTsKICAgIH0KCiAgICB2b2lkIGRpc2Nvbm5lY3RBbGwoKXsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIGRldGFpbDo6ZGlzY29ubmVjdEFsbChzbG90cywgaXNDdXJyZW50bHlFbWl0dGluZyk7CiAgICB9CgogICAgflNpZ25hbCgpeyBhc3NlcnQoaXNDdXJyZW50bHlFbWl0dGluZz09ZmFsc2UpOyBkaXNjb25uZWN0QWxsKCk7IH0gLy91cG9uIHJldHVybmluZyBmcm9tIGR0b3Igb2JqZWN0IGlzIGludmFsaWQgc28gYSBwZW5kaW5nIGVtaXQoKS1jYWxsIHdvdWxkIGJlIGludmFsaWQgdG9vIQoKICAgcHJpdmF0ZToKICAgIHR5cGVkZWYgdHlwZW5hbWUgZGV0YWlsOjpJbnZva2FibGVJbXBsPFI+Ojp0ZW1wbGF0ZSBCb3VuZEZ1bmN0aW9uPEExLCBBMj4gQXJnczsKICAgIHR5cGVkZWYgdHlwZW5hbWUgZGV0YWlsOjpJbnZva2FibGVJbXBsPFI+Ojp0ZW1wbGF0ZSBHbG9iYWxGdW5jdGlvbjxBMSwgQTI+IEdDYWxsZXI7CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmosIHR5cGVuYW1lIENvbnN0bmVzcz4KICAgIHN0cnVjdCBNQ2FsbGVyeyB0eXBlZGVmIHR5cGVuYW1lIGRldGFpbDo6SW52b2thYmxlSW1wbDxSPjo6dGVtcGxhdGUgTWVtYmVyRnVuY3Rpb248VE9iaiwgQ29uc3RuZXNzLCBBMSwgQTI+IHR5cGU7IH07CgogICAgdHlwZWRlZiBzdGQ6OnBhaXI8ZGV0YWlsOjpJbnZva2FibGU8UiwgQTEsIEEyPiosZGV0YWlsOjpEaXNjb25uZWN0aW9uUGVuZGluZz4gU2xvdDsKICAgIHR5cGVkZWYgdHlwZW5hbWUgZGV0YWlsOjpTbG90Q29udGFpbmVyPFNsb3Q+Ojp0eXBlIFNsb3RzOwoKICAgIHR5cGVkZWYgZGV0YWlsOjpNdXRleDo6dHlwZSBNdXRleF87CiAgICB0eXBlZGVmIGRldGFpbDo6U2NvcGVkTG9jazo6dHlwZSBTY29wZWRMb2NrXzsKCiAgICBib29sIGlzQ3VycmVudGx5RW1pdHRpbmcgPSBmYWxzZTsKICAgIFNsb3RzIHBlbmRpbmdDb25uZWN0czsKICAgIFNsb3RzIHNsb3RzOwogICAgTXV0ZXhfIHNsb3RzTXV0ZXg7Cn07CgoKCnRlbXBsYXRlIDx0eXBlbmFtZSBSLCB0eXBlbmFtZSBBMT4Kc3RydWN0IFNpZ25hbDxSKEExKT4gewoKICAgIHZvaWQgY29ubmVjdChSICgqbWVtYmVyKShBMSkpIHsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIGRldGFpbDo6Y29ubmVjdChpc0N1cnJlbnRseUVtaXR0aW5nID8gcGVuZGluZ0Nvbm5lY3RzIDogc2xvdHMsIFNsb3QobmV3IEdDYWxsZXIobWVtYmVyKSxkZXRhaWw6OmNvbm5lY3RlZCgpKSk7CiAgICB9CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmo+CiAgICB2b2lkIGNvbm5lY3QoVE9iaiYgb2JqLCBSIChUT2JqOjoqbWVtYmVyKShBMSkpIHsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIHR5cGVkZWYgdHlwZW5hbWUgTUNhbGxlcjxUT2JqLGRldGFpbDo6Tm9uQ29uc3Q+Ojp0eXBlIE1DYWxsZXJfOwogICAgICAgIGRldGFpbDo6Y29ubmVjdChpc0N1cnJlbnRseUVtaXR0aW5nID8gcGVuZGluZ0Nvbm5lY3RzIDogc2xvdHMsIFNsb3QobmV3IE1DYWxsZXJfKG9iaiwgbWVtYmVyKSxkZXRhaWw6OmNvbm5lY3RlZCgpKSk7CiAgICB9CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmo+CiAgICB2b2lkIGNvbm5lY3QoVE9iaiBjb25zdCYgb2JqLCBSIChUT2JqOjoqbWVtYmVyKShBMSkgY29uc3QpIHsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIHR5cGVkZWYgdHlwZW5hbWUgTUNhbGxlcjxjb25zdCBUT2JqLGRldGFpbDo6Q29uc3Q+Ojp0eXBlIE1DYWxsZXJfOwogICAgICAgIGRldGFpbDo6Y29ubmVjdChpc0N1cnJlbnRseUVtaXR0aW5nID8gcGVuZGluZ0Nvbm5lY3RzIDogc2xvdHMsIFNsb3QobmV3IE1DYWxsZXJfKG9iaiwgbWVtYmVyKSxkZXRhaWw6OmNvbm5lY3RlZCgpKSk7CiAgICB9CgogICAgZGV0YWlsOjpSZXR1cm5WYWx1ZUFnZ3JlZ2F0ZTxSPiBlbWl0KEExIGExKSB7CiAgICAgICAgU2NvcGVkTG9ja18gbG9jayhzbG90c011dGV4KTsKICAgICAgICBBcmdzIGFyZ3MoYTEpOwogICAgICAgIGRldGFpbDo6UmV0dXJuVmFsdWVBZ2dyZWdhdGU8Uj4gcjsKICAgICAgICBpZiAoaXNDdXJyZW50bHlFbWl0dGluZykgcmV0dXJuIHI7CiAgICAgICAgZGV0YWlsOjpTY29wZWRJbnZlcnNpb24gaW52ZXJ0ZXIoaXNDdXJyZW50bHlFbWl0dGluZyk7CiAgICAgICAgZGV0YWlsOjpSZXR1cm5WYWx1ZUFnZ3JlZ2F0b3I8Uj46Omludm9rZUFuZEFnZ3JlZ2F0ZShyLCBzbG90cywgYXJncyk7CiAgICAgICAgZGV0YWlsOjpkaXNjb25uZWN0UGVuZGluZyhzbG90cyk7CiAgICAgICAgZGV0YWlsOjpjb25uZWN0UGVuZGluZyhzbG90cywgcGVuZGluZ0Nvbm5lY3RzKTsKICAgICAgICByZXR1cm4gcjsKICAgIH0KCiAgICB2b2lkIGRpc2Nvbm5lY3QoUiAoKm1lbWJlcikoQTEpKSB7CiAgICAgICAgU2NvcGVkTG9ja18gbG9jayhzbG90c011dGV4KTsKICAgICAgICBkZXRhaWw6OmRpc2Nvbm5lY3Qoc2xvdHMsIGlzQ3VycmVudGx5RW1pdHRpbmcsIEdDYWxsZXIobWVtYmVyKSk7CiAgICB9CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmo+CiAgICB2b2lkIGRpc2Nvbm5lY3QoVE9iaiYgb2JqLCBSIChUT2JqOjoqbWVtYmVyKShBMSkpIHsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIHR5cGVkZWYgdHlwZW5hbWUgTUNhbGxlcjxUT2JqLGRldGFpbDo6Tm9uQ29uc3Q+Ojp0eXBlIE1DYWxsZXJfOwogICAgICAgIGRldGFpbDo6ZGlzY29ubmVjdChzbG90cywgaXNDdXJyZW50bHlFbWl0dGluZywgTUNhbGxlcl8ob2JqLG1lbWJlcikpOwogICAgfQoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUT2JqPgogICAgdm9pZCBkaXNjb25uZWN0KFRPYmogY29uc3QmIG9iaiwgUiAoVE9iajo6Km1lbWJlcikoQTEpIGNvbnN0KSB7CiAgICAgICAgU2NvcGVkTG9ja18gbG9jayhzbG90c011dGV4KTsKICAgICAgICB0eXBlZGVmIHR5cGVuYW1lIE1DYWxsZXI8Y29uc3QgVE9iaixkZXRhaWw6OkNvbnN0Pjo6dHlwZSBNQ2FsbGVyXzsKICAgICAgICBkZXRhaWw6OmRpc2Nvbm5lY3Qoc2xvdHMsIGlzQ3VycmVudGx5RW1pdHRpbmcsIE1DYWxsZXJfKG9iaixtZW1iZXIpKTsKICAgIH0KCiAgICB2b2lkIGRpc2Nvbm5lY3RBbGwoKXsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIGRldGFpbDo6ZGlzY29ubmVjdEFsbChzbG90cywgaXNDdXJyZW50bHlFbWl0dGluZyk7CiAgICB9CgogICAgflNpZ25hbCgpeyBhc3NlcnQoaXNDdXJyZW50bHlFbWl0dGluZz09ZmFsc2UpOyBkaXNjb25uZWN0QWxsKCk7IH0gLy91cG9uIHJldHVybmluZyBmcm9tIGR0b3Igb2JqZWN0IGlzIGludmFsaWQgc28gYSBwZW5kaW5nIGVtaXQoKS1jYWxsIHdvdWxkIGJlIGludmFsaWQgdG9vIQoKICAgcHJpdmF0ZToKICAgIHR5cGVkZWYgdHlwZW5hbWUgZGV0YWlsOjpJbnZva2FibGVJbXBsPFI+Ojp0ZW1wbGF0ZSBCb3VuZEZ1bmN0aW9uPEExPiBBcmdzOwogICAgdHlwZWRlZiB0eXBlbmFtZSBkZXRhaWw6Okludm9rYWJsZUltcGw8Uj46OnRlbXBsYXRlIEdsb2JhbEZ1bmN0aW9uPEExPiBHQ2FsbGVyOwoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUT2JqLCB0eXBlbmFtZSBDb25zdG5lc3M+CiAgICBzdHJ1Y3QgTUNhbGxlcnsgdHlwZWRlZiB0eXBlbmFtZSBkZXRhaWw6Okludm9rYWJsZUltcGw8Uj46OnRlbXBsYXRlIE1lbWJlckZ1bmN0aW9uPFRPYmosIENvbnN0bmVzcywgQTE+IHR5cGU7IH07CgogICAgdHlwZWRlZiBzdGQ6OnBhaXI8ZGV0YWlsOjpJbnZva2FibGU8UiwgQTE+KixkZXRhaWw6OkRpc2Nvbm5lY3Rpb25QZW5kaW5nPiBTbG90OwogICAgdHlwZWRlZiB0eXBlbmFtZSBkZXRhaWw6OlNsb3RDb250YWluZXI8U2xvdD46OnR5cGUgU2xvdHM7CgogICAgdHlwZWRlZiBkZXRhaWw6Ok11dGV4Ojp0eXBlIE11dGV4XzsKICAgIHR5cGVkZWYgZGV0YWlsOjpTY29wZWRMb2NrOjp0eXBlIFNjb3BlZExvY2tfOwoKICAgIGJvb2wgaXNDdXJyZW50bHlFbWl0dGluZyA9IGZhbHNlOwogICAgU2xvdHMgcGVuZGluZ0Nvbm5lY3RzOwogICAgU2xvdHMgc2xvdHM7CiAgICBNdXRleF8gc2xvdHNNdXRleDsKfTsKCgoKdGVtcGxhdGUgPHR5cGVuYW1lIFI+CnN0cnVjdCBTaWduYWw8UigpPiB7CgogICAgdm9pZCBjb25uZWN0KFIgKCptZW1iZXIpKCkpIHsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIGRldGFpbDo6Y29ubmVjdChpc0N1cnJlbnRseUVtaXR0aW5nID8gcGVuZGluZ0Nvbm5lY3RzIDogc2xvdHMsIFNsb3QobmV3IEdDYWxsZXIobWVtYmVyKSxkZXRhaWw6OmNvbm5lY3RlZCgpKSk7CiAgICB9CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmo+CiAgICB2b2lkIGNvbm5lY3QoVE9iaiYgb2JqLCBSIChUT2JqOjoqbWVtYmVyKSgpKSB7CiAgICAgICAgU2NvcGVkTG9ja18gbG9jayhzbG90c011dGV4KTsKICAgICAgICB0eXBlZGVmIHR5cGVuYW1lIE1DYWxsZXI8VE9iaixkZXRhaWw6Ok5vbkNvbnN0Pjo6dHlwZSBNQ2FsbGVyXzsKICAgICAgICBkZXRhaWw6OmNvbm5lY3QoaXNDdXJyZW50bHlFbWl0dGluZyA/IHBlbmRpbmdDb25uZWN0cyA6IHNsb3RzLCBTbG90KG5ldyBNQ2FsbGVyXyhvYmosIG1lbWJlciksZGV0YWlsOjpjb25uZWN0ZWQoKSkpOwogICAgfQoKICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBUT2JqPgogICAgdm9pZCBjb25uZWN0KFRPYmogY29uc3QmIG9iaiwgUiAoVE9iajo6Km1lbWJlcikoKSBjb25zdCkgewogICAgICAgIFNjb3BlZExvY2tfIGxvY2soc2xvdHNNdXRleCk7CiAgICAgICAgdHlwZWRlZiB0eXBlbmFtZSBNQ2FsbGVyPGNvbnN0IFRPYmosZGV0YWlsOjpDb25zdD46OnR5cGUgTUNhbGxlcl87CiAgICAgICAgZGV0YWlsOjpjb25uZWN0KGlzQ3VycmVudGx5RW1pdHRpbmcgPyBwZW5kaW5nQ29ubmVjdHMgOiBzbG90cywgU2xvdChuZXcgTUNhbGxlcl8ob2JqLCBtZW1iZXIpLGRldGFpbDo6Y29ubmVjdGVkKCkpKTsKICAgIH0KCiAgICBkZXRhaWw6OlJldHVyblZhbHVlQWdncmVnYXRlPFI+IGVtaXQoKSB7CiAgICAgICAgU2NvcGVkTG9ja18gbG9jayhzbG90c011dGV4KTsKICAgICAgICBBcmdzIGFyZ3M7CiAgICAgICAgZGV0YWlsOjpSZXR1cm5WYWx1ZUFnZ3JlZ2F0ZTxSPiByOwogICAgICAgIGlmIChpc0N1cnJlbnRseUVtaXR0aW5nKSByZXR1cm4gcjsKICAgICAgICBkZXRhaWw6OlNjb3BlZEludmVyc2lvbiBpbnZlcnRlcihpc0N1cnJlbnRseUVtaXR0aW5nKTsKICAgICAgICBkZXRhaWw6OlJldHVyblZhbHVlQWdncmVnYXRvcjxSPjo6aW52b2tlQW5kQWdncmVnYXRlKHIsIHNsb3RzLCBhcmdzKTsKICAgICAgICBkZXRhaWw6OmRpc2Nvbm5lY3RQZW5kaW5nKHNsb3RzKTsKICAgICAgICBkZXRhaWw6OmNvbm5lY3RQZW5kaW5nKHNsb3RzLCBwZW5kaW5nQ29ubmVjdHMpOwogICAgICAgIHJldHVybiByOwogICAgfQoKICAgIHZvaWQgZGlzY29ubmVjdChSICgqbWVtYmVyKSgpKSB7CiAgICAgICAgU2NvcGVkTG9ja18gbG9jayhzbG90c011dGV4KTsKICAgICAgICBkZXRhaWw6OmRpc2Nvbm5lY3Qoc2xvdHMsIGlzQ3VycmVudGx5RW1pdHRpbmcsIEdDYWxsZXIobWVtYmVyKSk7CiAgICB9CgogICAgdGVtcGxhdGUgPHR5cGVuYW1lIFRPYmo+CiAgICB2b2lkIGRpc2Nvbm5lY3QoVE9iaiYgb2JqLCBSIChUT2JqOjoqbWVtYmVyKSgpKSB7CiAgICAgICAgU2NvcGVkTG9ja18gbG9jayhzbG90c011dGV4KTsKICAgICAgICB0eXBlZGVmIHR5cGVuYW1lIE1DYWxsZXI8VE9iaixkZXRhaWw6Ok5vbkNvbnN0Pjo6dHlwZSBNQ2FsbGVyXzsKICAgICAgICBkZXRhaWw6OmRpc2Nvbm5lY3Qoc2xvdHMsIGlzQ3VycmVudGx5RW1pdHRpbmcsIE1DYWxsZXJfKG9iaixtZW1iZXIpKTsKICAgIH0KCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaj4KICAgIHZvaWQgZGlzY29ubmVjdChUT2JqIGNvbnN0JiBvYmosIFIgKFRPYmo6OiptZW1iZXIpKCkgY29uc3QpIHsKICAgICAgICBTY29wZWRMb2NrXyBsb2NrKHNsb3RzTXV0ZXgpOwogICAgICAgIHR5cGVkZWYgdHlwZW5hbWUgTUNhbGxlcjxjb25zdCBUT2JqLGRldGFpbDo6Q29uc3Q+Ojp0eXBlIE1DYWxsZXJfOwogICAgICAgIGRldGFpbDo6ZGlzY29ubmVjdChzbG90cywgaXNDdXJyZW50bHlFbWl0dGluZywgTUNhbGxlcl8ob2JqLG1lbWJlcikpOwogICAgfQoKICAgIHZvaWQgZGlzY29ubmVjdEFsbCgpewogICAgICAgIFNjb3BlZExvY2tfIGxvY2soc2xvdHNNdXRleCk7CiAgICAgICAgZGV0YWlsOjpkaXNjb25uZWN0QWxsKHNsb3RzLCBpc0N1cnJlbnRseUVtaXR0aW5nKTsKICAgIH0KCiAgICB+U2lnbmFsKCl7IGFzc2VydChpc0N1cnJlbnRseUVtaXR0aW5nPT1mYWxzZSk7IGRpc2Nvbm5lY3RBbGwoKTsgfSAvL3Vwb24gcmV0dXJuaW5nIGZyb20gZHRvciBvYmplY3QgaXMgaW52YWxpZCBzbyBhIHBlbmRpbmcgZW1pdCgpLWNhbGwgd291bGQgYmUgaW52YWxpZCB0b28hCgogICBwcml2YXRlOgogICAgdHlwZWRlZiB0eXBlbmFtZSBkZXRhaWw6Okludm9rYWJsZUltcGw8Uj46OnRlbXBsYXRlIEJvdW5kRnVuY3Rpb248dm9pZCwgdm9pZCwgdm9pZCwgdm9pZCwgdm9pZCwgZGV0YWlsOjpOb25EZWZhdWx0PiBBcmdzOwogICAgdHlwZWRlZiB0eXBlbmFtZSBkZXRhaWw6Okludm9rYWJsZUltcGw8Uj46OnRlbXBsYXRlIEdsb2JhbEZ1bmN0aW9uPHZvaWQsIHZvaWQsIHZvaWQsIHZvaWQsIHZvaWQsIGRldGFpbDo6Tm9uRGVmYXVsdD4gR0NhbGxlcjsKCiAgICB0ZW1wbGF0ZSA8dHlwZW5hbWUgVE9iaiwgdHlwZW5hbWUgQ29uc3RuZXNzPgogICAgc3RydWN0IE1DYWxsZXJ7IHR5cGVkZWYgdHlwZW5hbWUgZGV0YWlsOjpJbnZva2FibGVJbXBsPFI+Ojp0ZW1wbGF0ZSBNZW1iZXJGdW5jdGlvbjxUT2JqLCBDb25zdG5lc3M+IHR5cGU7IH07CgogICAgdHlwZWRlZiBzdGQ6OnBhaXI8ZGV0YWlsOjpJbnZva2FibGU8Uj4qLGRldGFpbDo6RGlzY29ubmVjdGlvblBlbmRpbmc+IFNsb3Q7CiAgICB0eXBlZGVmIHR5cGVuYW1lIGRldGFpbDo6U2xvdENvbnRhaW5lcjxTbG90Pjo6dHlwZSBTbG90czsKCiAgICB0eXBlZGVmIGRldGFpbDo6TXV0ZXg6OnR5cGUgTXV0ZXhfOwogICAgdHlwZWRlZiBkZXRhaWw6OlNjb3BlZExvY2s6OnR5cGUgU2NvcGVkTG9ja187CgogICAgYm9vbCBpc0N1cnJlbnRseUVtaXR0aW5nID0gZmFsc2U7CiAgICBTbG90cyBwZW5kaW5nQ29ubmVjdHM7CiAgICBTbG90cyBzbG90czsKICAgIE11dGV4XyBzbG90c011dGV4Owp9OwoKCgoKCgp9ICAvLyBuYW1lc3BhY2Ugc2lzbAoKCnVzaW5nIG5hbWVzcGFjZSBzaXNsOwoKc3RydWN0IFRyYWZpY0xpZ2h0ewoKICAgIFNpZ25hbDx2b2lkKCk+IGdyZWVuOwogICAgU2lnbmFsPHZvaWQoKT4gcmVkOwoKICAgIHZvaWQgc3dpdGNoVG9HcmVlbigpewogICAgICAgIHN0ZDo6Y291dDw8Ij09PXN3aXRjaGluZyB0byBncmVlbj09PVxuIjsKICAgICAgICBncmVlbi5lbWl0KCk7CiAgICB9CiAgICB2b2lkIHN3aXRjaFRvUmVkKCl7CiAgICAgICAgc3RkOjpjb3V0PDwiPT09c3dpdGNoaW5nIHRvIHJlZD09PVxuIjsKICAgICAgICByZWQuZW1pdCgpOwogICAgfQp9OwoKCnN0cnVjdCBQZWRlc3RyaWFuewogICAgdm9pZCB3YWxrKCl7c3RkOjpjb3V0PDwiUGVkZXN0cmlhbiB3YWxrXG4iO30KICAgIHZvaWQgd2FpdCgpe3N0ZDo6Y291dDw8IlBlZGVzdHJpYW4gd2FpdFxuIjt9Cn07CgoKaW50IG1haW4oKQp7CiAgICAvL2NyZWF0ZSBpbnN0YW5jZXMKICAgIFRyYWZpY0xpZ2h0IHRsOwogICAgUGVkZXN0cmlhbiBwOwoKICAgIC8vbGluawogICAgdGwuZ3JlZW4uY29ubmVjdChwLCZQZWRlc3RyaWFuOjp3YWl0KTsKICAgIHRsLnJlZC5jb25uZWN0KHAsJlBlZGVzdHJpYW46OndhbGspOwoKICAgIC8vYmVnaW4gb3BlcmF0aW9uCiAgICB0bC5zd2l0Y2hUb1JlZCgpOwogICAgdGwuc3dpdGNoVG9HcmVlbigpOwoKICAgIHJldHVybiAwOwp9Cgo=