#include <iostream>
#include <type_traits>
template < std:: size_t ...> struct index_sequence { } ;
template < std:: size_t N, std:: size_t ... Is >
struct make_index_sequence_helper : make_index_sequence_helper< N- 1 , N- 1 , Is...> { } ;
template < std:: size_t ... Is >
struct make_index_sequence_helper< 0 , Is...> {
using type = index_sequence< Is...> ;
} ;
template < std:: size_t N>
using make_index_sequence = typename make_index_sequence_helper< N> :: type ;
// Merging packs.
template < typename , typename ...> struct Merge;
template < typename T, template < T...> class P1, template < T...> class P2, T... Is , T... Js >
struct Merge< T, P1< Is...> , P2< Js...>> {
using type = P1< Is..., Js...> ;
} ;
template < typename T, typename First, typename ... Rest >
struct Merge< T, First, Rest...> : Merge< T, First, typename Merge< T, Rest...> :: type > { } ;
// Checking if t of type T exists in a pack of T objects.
template < typename T, T t, T...> struct ExistsInPack;
template < typename T, T t, T First, T... Rest >
struct ExistsInPack< T, t, First, Rest...> : ExistsInPack< T, t, Rest...> { } ;
template < typename T, T t, T... Rest >
struct ExistsInPack< T, t, t, Rest...> : std:: true_type { } ;
template < typename T, T t>
struct ExistsInPack< T, t> : std:: false_type { } ;
// Removing duplicates from a pack.
template < typename , typename , typename > struct RemoveDuplicatesHelper;
template < typename T, template < T...> class P, T First, T... Rest , T... Accumulated >
struct RemoveDuplicatesHelper< T, P< First, Rest...> , P< Accumulated...>> : std:: conditional < ExistsInPack< T, First, Accumulated..., Rest...> :: value ,
RemoveDuplicatesHelper< T, P< Rest...> , P< Accumulated...>> ,
RemoveDuplicatesHelper< T, P< Rest...> , P< Accumulated..., First>>
> :: type { } ;
template < typename T, template < T...> class P, T... Accumulated >
struct RemoveDuplicatesHelper< T, P<> , P< Accumulated...>> {
using type = P< Accumulated...> ;
} ;
template < typename , typename > struct RemoveDuplicates;
template < typename T, template < T...> class P, T... Ts >
struct RemoveDuplicates< T, P< Ts...>> : RemoveDuplicatesHelper< T, P< Ts...> , P<>> { } ;
// Obtaining the adjacent vertices of a given vertex.
template < std:: size_t , typename , typename > struct AdjacentVerticesHelper;
template < std:: size_t Vertex, template < std:: size_t ...> class P, std:: size_t From, std:: size_t To, std:: size_t ... RemainingPairs , std:: size_t ... Accumulated >
struct AdjacentVerticesHelper< Vertex, P< From, To, RemainingPairs...> , P< Accumulated...>> : AdjacentVerticesHelper< Vertex, P< RemainingPairs...> , P< Accumulated...>> { } ;
template < std:: size_t Vertex, template < std:: size_t ...> class P, std:: size_t To, std:: size_t ... RemainingPairs , std:: size_t ... Accumulated >
struct AdjacentVerticesHelper< Vertex, P< Vertex, To, RemainingPairs...> , P< Accumulated...>> : AdjacentVerticesHelper< Vertex, P< RemainingPairs...> , P< Accumulated..., To>> { } ;
template < std:: size_t Vertex, template < std:: size_t ...> class P, std:: size_t ... Accumulated >
struct AdjacentVerticesHelper< Vertex, P<> , P< Accumulated...>> {
using type = P< Accumulated...> ;
static const bool nonempty = sizeof ...( Accumulated) > 0 ;
} ;
template < std:: size_t , typename > struct AdjacentVertices;
template < std:: size_t Vertex, template < std:: size_t ...> class P, std:: size_t ... Edges >
struct AdjacentVertices< Vertex, P< Edges...>> : AdjacentVerticesHelper< Vertex, P< Edges...> , P<>> { } ;
// Removing from a pack all the elements in P<Visited...>.
template < typename , typename , typename , typename > struct RemoveThoseAlreadyVisitedHelper;
template < typename T, template < T...> class P, T First, T... Rest , T... Visited , T... Accumulated >
struct RemoveThoseAlreadyVisitedHelper< T, P< First, Rest...> , P< Visited...> , P< Accumulated...>> : std:: conditional < ExistsInPack< T, First, Visited...> :: value ,
RemoveThoseAlreadyVisitedHelper< T, P< Rest...> , P< Visited...> , P< Accumulated...>> ,
RemoveThoseAlreadyVisitedHelper< T, P< Rest...> , P< Visited...> , P< Accumulated..., First>>
> :: type { } ;
template < typename T, template < T...> class P, T... Visited , T... Accumulated >
struct RemoveThoseAlreadyVisitedHelper< T, P<> , P< Visited...> , P< Accumulated...>> {
using type = P< Accumulated...> ;
} ;
template < typename , typename , typename > struct RemoveThoseAlreadyVisited;
template < typename T, template < T...> class P, T... Ts , T... Visited >
struct RemoveThoseAlreadyVisited< T, P< Ts...> , P< Visited...>> : RemoveThoseAlreadyVisitedHelper< T, P< Ts...> , P< Visited...> , P<>> { } ;
template < typename T, template < T...> class P, T... Ts >
struct RemoveThoseAlreadyVisited< T, P< Ts...> , P<>> { // These remaining specializations are to avoid using the above specialization since 'type' is immediately obvious and needs no computation.
using type = P< Ts...> ;
} ;
template < typename T, template < T...> class P, T... Visited >
struct RemoveThoseAlreadyVisited< T, P<> , P< Visited...>> {
using type = P<> ;
} ;
template < typename T, template < T...> class P>
struct RemoveThoseAlreadyVisited< T, P<> , P<>> { // This is needed to avoid ambiguity with the above two specializations.
using type = P<> ;
} ;
// Now the main structs.
template < typename , typename , typename , typename , typename > struct TopologicalSort;
template < typename , typename , typename , typename , typename , typename > struct TopologicalSortHelper;
template < typename , typename , typename , typename , typename , typename > struct UpdateStack;
template < typename , typename , typename , typename , typename > struct ReturnToTopologicalSort;
// End of the topological sort loop. Replacing P<Visited...> with typename Visited and/or P<Edges...> with typename Edges and/or P<Vertices...> with typename Stack will cause ambiguity compiling error since neither this nor the above partial specialization is more specialized than the other.
template < typename T, template < T...> class P, T... Visited , T... Edges , T... Vertices >
struct TopologicalSort< T, P<> , P< Edges...> , P< Visited...> , P< Vertices...>> {
using topological_sort = P< Vertices...> ; // The final stack of vertices describing a topological order.
using visited = P< Visited...> ; // This is just to check that P<Visited...> does not have repeats (to ensure optimal performance).
} ;
// The topological sort loop.
template < typename T, template < T...> class P, T First, T... Rest , T... Visited , T... Edges , T... Vertices > // First, Rest... are the vertices to be visited now (in that order).
struct TopologicalSort< T, P< First, Rest...> , P< Edges...> , P< Visited...> , P< Vertices...>> :
TopologicalSortHelper< T, P< First, Rest...> , P< Edges...> , P< Visited..., First> , P< Vertices...> , // Append First to P<Visited...>.
typename RemoveThoseAlreadyVisited< T, typename AdjacentVertices< First, P< Edges...>> :: type , P< Visited...>> :: type > { } ; // Pass the adjacent vertices of First (if any), except those that have already been visited.
// The first type in ToVisit... has adjacent edges, so visit its adjacent vertices, and prepend this first type to P<Vertices...> AFTER these visits.
template < typename T, template < T...> class P, T... ToVisit , T... Visited , T... Edges , T... Vertices , typename AdjacentVertices>
struct TopologicalSortHelper< T, P< ToVisit...> , P< Edges...> , P< Visited...> , P< Vertices...> , AdjacentVertices> :
UpdateStack< T, P< ToVisit...> , P< Edges...> , P< Visited...> , P< Vertices...> , TopologicalSort< T, AdjacentVertices, P< Edges...> , P< Visited...> , P<>>> { } ; // Must use P<> instead of P<Vertices...> here, because we are going to adjoin the topological_sort of this particular subtree to P<Vertices...>.
// First has no adjacent vertices, so prepend it to P<Vertices...>. Simply prepend First to P<Vertices...>, and move on to Rest...
template < typename T, template < T...> class P, T First, T... Rest , T... Visited , T... Edges , T... Vertices >
struct TopologicalSortHelper< T, P< First, Rest...> , P< Edges...> , P< Visited...> , P< Vertices...> , P<>> : TopologicalSort< T, P< Rest...> , P< Edges...> , P< Visited...> , P< First, Vertices...>> { } ;
// Updating P<Vertices...> after all adjacent (unvisited) edges have been visited.
template < typename T, template < T...> class P, T First, T... Rest , T... Visited , T... Edges , T... Vertices , typename AdjacentEdgesTopologicalSort>
struct UpdateStack< T, P< First, Rest...> , P< Edges...> , P< Visited...> , P< Vertices...> , AdjacentEdgesTopologicalSort> :
ReturnToTopologicalSort< T, P< Rest...> , P< Edges...> ,
typename RemoveDuplicates< T, typename Merge< T, P< Visited...> , typename AdjacentEdgesTopologicalSort:: visited > :: type > :: type , // RemoveDuplicates is actually not necessarily (the results are still correct without it), but without it the P<Visited...> will have many duplicates in general and thus lead to slower computation of RemoveThoseAlreadyVisited.
typename Merge< T, P< First> , typename AdjacentEdgesTopologicalSort:: topological_sort , P< Vertices...>> :: type // Wrapping the merge result with RemoveDuplicates is apparently not necessary, as it is apparently mathematically impossible for there to be duplicates after this merge.
> { } ;
// Return to TopologicalSort, but first remove from ToVisit... all those that are in Visited...
template < typename T, template < T...> class P, T... ToVisit , T... Visited , T... Edges , T... Vertices >
struct ReturnToTopologicalSort< T, P< ToVisit...> , P< Edges...> , P< Visited...> , P< Vertices...>> :
TopologicalSort< T, typename RemoveThoseAlreadyVisited< T, P< ToVisit...> , P< Visited...>> :: type , P< Edges...> , P< Visited...> , P< Vertices...>> { } ; // RemoveThoseAlreadyVisited is absolutely necesary.
// Now the Graph classes themselves.
template < std:: size_t N, std:: size_t ... Edges >
struct Graph1 : TopologicalSort< std:: size_t , make_index_sequence< N> , index_sequence< Edges...> , index_sequence<> , index_sequence<>> { } ;
// Sorter class needed for class Graph2, where the vertices can be non-consecutive integers, and the number of vertices does not need to be specified.
template < std:: size_t I, std:: size_t J>
struct IntLessThan : std:: conditional < ( I < J) , std:: true_type , std:: false_type > :: type { } ;
template < std:: size_t , typename > struct PrependInt;
template < std:: size_t N, template < std:: size_t ...> class Z, std:: size_t ... Is >
struct PrependInt< N, Z< Is...>> {
using type = Z< N, Is...> ;
} ;
template < template < std:: size_t > class , typename > struct FilterInts;
template < template < std:: size_t > class F, template < std:: size_t ...> class Z, std:: size_t I, std:: size_t ... Is >
struct FilterInts< F, Z< I, Is...>> {
using type = typename std:: conditional < F< I> :: value ,
typename PrependInt< I, typename FilterInts< F, Z< Is...>> :: type > :: type ,
typename FilterInts< F, Z< Is...>> :: type
> :: type ;
} ;
template < template < std:: size_t > class F, template < std:: size_t ...> class Z>
struct FilterInts< F, Z<>> {
using type = Z<> ;
} ;
template < typename , typename > struct MergeIntSequences;
template < template < std:: size_t ...> class Z, std:: size_t ... Is , std:: size_t ... Js >
struct MergeIntSequences< Z< Is...> , Z< Js...>> {
using type = Z< Is..., Js...> ;
} ;
template < typename , template < std:: size_t , std:: size_t > class = IntLessThan> struct SortIntSequence;
template < template < std:: size_t ...> class Z, std:: size_t N, std:: size_t ... Is , template < std:: size_t , std:: size_t > class Comparator>
struct SortIntSequence< Z< N, Is...> , Comparator> {
template < std:: size_t I> struct less_than : std:: integral_constant < bool , Comparator< I,N> :: value > { } ;
template < std:: size_t I> struct more_than : std:: integral_constant < bool , Comparator< N,I> :: value || I == N> { } ;
using subsequence_less_than_N = typename FilterInts< less_than, Z< Is...>> :: type ;
using subsequence_more_than_N = typename FilterInts< more_than, Z< Is...>> :: type ;
using type = typename MergeIntSequences< typename SortIntSequence< subsequence_less_than_N, Comparator> :: type ,
typename PrependInt< N, typename SortIntSequence< subsequence_more_than_N, Comparator> :: type > :: type
> :: type ;
} ;
template < template < std:: size_t ...> class Z, template < std:: size_t , std:: size_t > class Comparator>
struct SortIntSequence< Z<> , Comparator> {
using type = Z<> ;
} ;
// Graph2 is more flexible than Graph1 because the vertices can be non-consecutive integers, and the number of vertices does not need to be specified since that can be deduced by the vertices.
template < std:: size_t ... Edges >
struct Graph2 : TopologicalSort< std:: size_t , typename SortIntSequence< typename RemoveDuplicates< std:: size_t , index_sequence< Edges...>> :: type > :: type , // All duplicates removed, and the vertices MUST be sorted for this to compile (though I didn't bother tracing why). Of course, the vertices in Graph1 are already sorted.
index_sequence< Edges...> , index_sequence<> , index_sequence<>> { } ;
// -------------------------- Testing --------------------------
template < std:: size_t Last>
struct index_sequence< Last> {
static void print( ) { std:: cout << Last << std:: endl ; }
} ;
template < std:: size_t First, std:: size_t ... Rest >
struct index_sequence< First, Rest...> {
static void print( ) { std:: cout << First << ' ' ; index_sequence< Rest...> :: print ( ) ; }
} ;
int main( ) {
using DAG1 = Graph1< 6 , 5 ,2 , 5 ,0 , 4 ,0 , 4 ,1 , 2 ,3 , 3 ,1 > ;
std:: cout << "Topological sort of DAG1: " ; DAG1:: topological_sort :: print ( ) ; // 5 4 2 3 1 0 (identical to the run-time solution at the top)
std:: cout << "Vertices visited in DAG1: " ; DAG1:: visited :: print ( ) ; // 1 2 3 4 5 (no repeats)
std:: cout << std:: boolalpha << std:: is_same < DAG1:: topological_sort , index_sequence< 5 ,4 ,2 ,3 ,1 ,0 >> :: value << std:: endl ; // true
using DAG2 = Graph1< 8 , 0 ,1 , 0 ,2 , 0 ,3 , 1 ,4 , 1 ,5 , 2 ,4 , 2 ,6 , 3 ,5 , 3 ,6 , 4 ,7 , 5 ,7 , 6 ,7 > ;
std:: cout << "\n Topological sort of DAG2: " ; DAG2:: topological_sort :: print ( ) ; // 0 3 2 6 1 5 4 7 (identical to the run-time solution at the top)
std:: cout << "Vertices visited in DAG2: " ; DAG2:: visited :: print ( ) ; // 0 1 4 7 5 2 6 3 (no repeats)
std:: cout << std:: is_same < DAG2:: topological_sort , index_sequence< 0 ,3 ,2 ,6 ,1 ,5 ,4 ,7 >> :: value << std:: endl ; // true
using DAG3 = Graph1< 8 , 5 ,1 , 1 ,2 , 1 ,0 , 1 ,6 , 7 ,1 , 7 ,4 , 4 ,6 , 3 ,0 , 3 ,4 > ; // This has the same edges as DAG5, with 11 renamed to 1, 10 renamed to 0, 9 renamed to 6, and 8 renamed to 4.
std:: cout << "\n Topological sort of DAG3: " ; DAG3:: topological_sort :: print ( ) ; // 7 5 3 4 1 6 2 0 (identical to the run-time solution at the top)
std:: cout << "Vertices visited in DAG3: " ; DAG3:: visited :: print ( ) ; // 0 1 2 6 3 4 5 7 (no repeats)
std:: cout << std:: is_same < DAG3:: topological_sort , index_sequence< 7 ,5 ,3 ,4 ,1 ,6 ,2 ,0 >> :: value << std:: endl ; // true
std:: cout << "\n \n Using Graph2:" << std:: endl ;
using DAG4 = Graph2< 0 ,1 , 0 ,2 , 0 ,3 , 1 ,4 , 1 ,5 , 2 ,4 , 2 ,6 , 3 ,5 , 3 ,6 , 4 ,7 , 5 ,7 , 6 ,7 > ;
DAG4:: topological_sort :: print ( ) ; // 0 3 2 6 1 5 4 7 (same solution as DAG2 using the Graph1 class)
std:: cout << std:: is_same < DAG4:: topological_sort , index_sequence< 0 ,3 ,2 ,6 ,1 ,5 ,4 ,7 >> :: value << std:: endl ; // true
using DAG5 = Graph2< 5 ,11 , 11 ,2 , 11 ,10 , 11 ,9 , 7 ,11 , 7 ,8 , 8 ,9 , 3 ,10 , 3 ,8 > ; // See the first diagram in http://e...content-available-to-author-only...a.org/wiki/Directed_acyclic_graph for a picture of this graph.
DAG5:: topological_sort :: print ( ) ; // 7 5 11 3 8 9 10 2 (this is indeed a valid topological sort)
using DAG6 = Graph2< 5 ,1 , 1 ,2 , 1 ,0 , 1 ,6 , 7 ,1 , 7 ,4 , 4 ,6 , 3 ,0 , 3 ,4 > ; // This Graph2 type has the same edges as DAG5, with 11 renamed to 1, 10 renamed to 0, 9 renamed to 6, and 8 renamed to 4.
DAG6:: topological_sort :: print ( ) ; // 7 5 3 4 1 6 2 0 (identical to the run-time solution at the top)
std:: cout << std:: is_same < DAG6:: topological_sort , index_sequence< 7 ,5 ,3 ,4 ,1 ,6 ,2 ,0 >> :: value << std:: endl ; // true
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dHlwZV90cmFpdHM+Cgp0ZW1wbGF0ZSA8c3RkOjpzaXplX3QuLi4+IHN0cnVjdCBpbmRleF9zZXF1ZW5jZSB7fTsKCnRlbXBsYXRlIDxzdGQ6OnNpemVfdCBOLCBzdGQ6OnNpemVfdC4uLiBJcz4Kc3RydWN0IG1ha2VfaW5kZXhfc2VxdWVuY2VfaGVscGVyIDogbWFrZV9pbmRleF9zZXF1ZW5jZV9oZWxwZXI8Ti0xLCBOLTEsIElzLi4uPiB7fTsKCnRlbXBsYXRlIDxzdGQ6OnNpemVfdC4uLiBJcz4Kc3RydWN0IG1ha2VfaW5kZXhfc2VxdWVuY2VfaGVscGVyPDAsIElzLi4uPiB7CiAgICB1c2luZyB0eXBlID0gaW5kZXhfc2VxdWVuY2U8SXMuLi4+Owp9OwoKdGVtcGxhdGUgPHN0ZDo6c2l6ZV90IE4+CnVzaW5nIG1ha2VfaW5kZXhfc2VxdWVuY2UgPSB0eXBlbmFtZSBtYWtlX2luZGV4X3NlcXVlbmNlX2hlbHBlcjxOPjo6dHlwZTsKCi8vIE1lcmdpbmcgcGFja3MuCnRlbXBsYXRlIDx0eXBlbmFtZSwgdHlwZW5hbWUuLi4+IHN0cnVjdCBNZXJnZTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBULCB0ZW1wbGF0ZSA8VC4uLj4gY2xhc3MgUDEsIHRlbXBsYXRlIDxULi4uPiBjbGFzcyBQMiwgVC4uLiBJcywgVC4uLiBKcz4Kc3RydWN0IE1lcmdlPFQsIFAxPElzLi4uPiwgUDI8SnMuLi4+PiB7Cgl1c2luZyB0eXBlID0gUDE8SXMuLi4sIEpzLi4uPjsKfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBULCB0eXBlbmFtZSBGaXJzdCwgdHlwZW5hbWUuLi4gUmVzdD4Kc3RydWN0IE1lcmdlPFQsIEZpcnN0LCBSZXN0Li4uPiA6IE1lcmdlPFQsIEZpcnN0LCB0eXBlbmFtZSBNZXJnZTxULCBSZXN0Li4uPjo6dHlwZT4ge307CgovLyBDaGVja2luZyBpZiB0IG9mIHR5cGUgVCBleGlzdHMgaW4gYSBwYWNrIG9mIFQgb2JqZWN0cy4KdGVtcGxhdGUgPHR5cGVuYW1lIFQsIFQgdCwgVC4uLj4gc3RydWN0IEV4aXN0c0luUGFjazsKCnRlbXBsYXRlIDx0eXBlbmFtZSBULCBUIHQsIFQgRmlyc3QsIFQuLi4gUmVzdD4Kc3RydWN0IEV4aXN0c0luUGFjazxULCB0LCBGaXJzdCwgUmVzdC4uLj4gOiBFeGlzdHNJblBhY2s8VCwgdCwgUmVzdC4uLj4ge307Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgVCB0LCBULi4uIFJlc3Q+CnN0cnVjdCBFeGlzdHNJblBhY2s8VCwgdCwgdCwgUmVzdC4uLj4gOiBzdGQ6OnRydWVfdHlwZSB7fTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBULCBUIHQ+CnN0cnVjdCBFeGlzdHNJblBhY2s8VCwgdD4gOiBzdGQ6OmZhbHNlX3R5cGUge307CgovLyBSZW1vdmluZyBkdXBsaWNhdGVzIGZyb20gYSBwYWNrLgp0ZW1wbGF0ZSA8dHlwZW5hbWUsIHR5cGVuYW1lLCB0eXBlbmFtZT4gc3RydWN0IFJlbW92ZUR1cGxpY2F0ZXNIZWxwZXI7Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgdGVtcGxhdGUgPFQuLi4+IGNsYXNzIFAsIFQgRmlyc3QsIFQuLi4gUmVzdCwgVC4uLiBBY2N1bXVsYXRlZD4Kc3RydWN0IFJlbW92ZUR1cGxpY2F0ZXNIZWxwZXI8VCwgUDxGaXJzdCwgUmVzdC4uLj4sIFA8QWNjdW11bGF0ZWQuLi4+PiA6IHN0ZDo6Y29uZGl0aW9uYWw8RXhpc3RzSW5QYWNrPFQsIEZpcnN0LCBBY2N1bXVsYXRlZC4uLiwgUmVzdC4uLj46OnZhbHVlLAoJCVJlbW92ZUR1cGxpY2F0ZXNIZWxwZXI8VCwgUDxSZXN0Li4uPiwgUDxBY2N1bXVsYXRlZC4uLj4+LAoJCVJlbW92ZUR1cGxpY2F0ZXNIZWxwZXI8VCwgUDxSZXN0Li4uPiwgUDxBY2N1bXVsYXRlZC4uLiwgRmlyc3Q+PgoJPjo6dHlwZSB7fTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBULCB0ZW1wbGF0ZSA8VC4uLj4gY2xhc3MgUCwgVC4uLiBBY2N1bXVsYXRlZD4Kc3RydWN0IFJlbW92ZUR1cGxpY2F0ZXNIZWxwZXI8VCwgUDw+LCBQPEFjY3VtdWxhdGVkLi4uPj4gewoJdXNpbmcgdHlwZSA9IFA8QWNjdW11bGF0ZWQuLi4+Owp9OwoKdGVtcGxhdGUgPHR5cGVuYW1lLCB0eXBlbmFtZT4gc3RydWN0IFJlbW92ZUR1cGxpY2F0ZXM7Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgdGVtcGxhdGUgPFQuLi4+IGNsYXNzIFAsIFQuLi4gVHM+CnN0cnVjdCBSZW1vdmVEdXBsaWNhdGVzPFQsIFA8VHMuLi4+PiA6IFJlbW92ZUR1cGxpY2F0ZXNIZWxwZXI8VCwgUDxUcy4uLj4sIFA8Pj4ge307CgovLyBPYnRhaW5pbmcgdGhlIGFkamFjZW50IHZlcnRpY2VzIG9mIGEgZ2l2ZW4gdmVydGV4Lgp0ZW1wbGF0ZSA8c3RkOjpzaXplX3QsIHR5cGVuYW1lLCB0eXBlbmFtZT4gc3RydWN0IEFkamFjZW50VmVydGljZXNIZWxwZXI7Cgp0ZW1wbGF0ZSA8c3RkOjpzaXplX3QgVmVydGV4LCB0ZW1wbGF0ZSA8c3RkOjpzaXplX3QuLi4+IGNsYXNzIFAsIHN0ZDo6c2l6ZV90IEZyb20sIHN0ZDo6c2l6ZV90IFRvLCBzdGQ6OnNpemVfdC4uLiBSZW1haW5pbmdQYWlycywgc3RkOjpzaXplX3QuLi4gQWNjdW11bGF0ZWQ+CnN0cnVjdCBBZGphY2VudFZlcnRpY2VzSGVscGVyPFZlcnRleCwgUDxGcm9tLCBUbywgUmVtYWluaW5nUGFpcnMuLi4+LCBQPEFjY3VtdWxhdGVkLi4uPj4gOiBBZGphY2VudFZlcnRpY2VzSGVscGVyPFZlcnRleCwgUDxSZW1haW5pbmdQYWlycy4uLj4sIFA8QWNjdW11bGF0ZWQuLi4+PiB7fTsKCnRlbXBsYXRlIDxzdGQ6OnNpemVfdCBWZXJ0ZXgsIHRlbXBsYXRlIDxzdGQ6OnNpemVfdC4uLj4gY2xhc3MgUCwgc3RkOjpzaXplX3QgVG8sIHN0ZDo6c2l6ZV90Li4uIFJlbWFpbmluZ1BhaXJzLCBzdGQ6OnNpemVfdC4uLiBBY2N1bXVsYXRlZD4Kc3RydWN0IEFkamFjZW50VmVydGljZXNIZWxwZXI8VmVydGV4LCBQPFZlcnRleCwgVG8sIFJlbWFpbmluZ1BhaXJzLi4uPiwgUDxBY2N1bXVsYXRlZC4uLj4+IDogQWRqYWNlbnRWZXJ0aWNlc0hlbHBlcjxWZXJ0ZXgsIFA8UmVtYWluaW5nUGFpcnMuLi4+LCBQPEFjY3VtdWxhdGVkLi4uLCBUbz4+IHt9OwoKdGVtcGxhdGUgPHN0ZDo6c2l6ZV90IFZlcnRleCwgdGVtcGxhdGUgPHN0ZDo6c2l6ZV90Li4uPiBjbGFzcyBQLCBzdGQ6OnNpemVfdC4uLiBBY2N1bXVsYXRlZD4Kc3RydWN0IEFkamFjZW50VmVydGljZXNIZWxwZXI8VmVydGV4LCBQPD4sIFA8QWNjdW11bGF0ZWQuLi4+PiB7Cgl1c2luZyB0eXBlID0gUDxBY2N1bXVsYXRlZC4uLj47CglzdGF0aWMgY29uc3QgYm9vbCBub25lbXB0eSA9IHNpemVvZi4uLihBY2N1bXVsYXRlZCkgPiAwOwp9OwoKdGVtcGxhdGUgPHN0ZDo6c2l6ZV90LCB0eXBlbmFtZT4gc3RydWN0IEFkamFjZW50VmVydGljZXM7Cgp0ZW1wbGF0ZSA8c3RkOjpzaXplX3QgVmVydGV4LCB0ZW1wbGF0ZSA8c3RkOjpzaXplX3QuLi4+IGNsYXNzIFAsIHN0ZDo6c2l6ZV90Li4uIEVkZ2VzPgpzdHJ1Y3QgQWRqYWNlbnRWZXJ0aWNlczxWZXJ0ZXgsIFA8RWRnZXMuLi4+PiA6IEFkamFjZW50VmVydGljZXNIZWxwZXI8VmVydGV4LCBQPEVkZ2VzLi4uPiwgUDw+PiB7fTsKCi8vIFJlbW92aW5nIGZyb20gYSBwYWNrIGFsbCB0aGUgZWxlbWVudHMgaW4gUDxWaXNpdGVkLi4uPi4KdGVtcGxhdGUgPHR5cGVuYW1lLCB0eXBlbmFtZSwgdHlwZW5hbWUsIHR5cGVuYW1lPiBzdHJ1Y3QgUmVtb3ZlVGhvc2VBbHJlYWR5VmlzaXRlZEhlbHBlcjsKCnRlbXBsYXRlIDx0eXBlbmFtZSBULCB0ZW1wbGF0ZSA8VC4uLj4gY2xhc3MgUCwgVCBGaXJzdCwgVC4uLiBSZXN0LCBULi4uIFZpc2l0ZWQsIFQuLi4gQWNjdW11bGF0ZWQ+CnN0cnVjdCBSZW1vdmVUaG9zZUFscmVhZHlWaXNpdGVkSGVscGVyPFQsIFA8Rmlyc3QsIFJlc3QuLi4+LCBQPFZpc2l0ZWQuLi4+LCBQPEFjY3VtdWxhdGVkLi4uPj4gOiBzdGQ6OmNvbmRpdGlvbmFsPEV4aXN0c0luUGFjazxULCBGaXJzdCwgVmlzaXRlZC4uLj46OnZhbHVlLAoJCVJlbW92ZVRob3NlQWxyZWFkeVZpc2l0ZWRIZWxwZXI8VCwgUDxSZXN0Li4uPiwgUDxWaXNpdGVkLi4uPiwgUDxBY2N1bXVsYXRlZC4uLj4+LAoJCVJlbW92ZVRob3NlQWxyZWFkeVZpc2l0ZWRIZWxwZXI8VCwgUDxSZXN0Li4uPiwgUDxWaXNpdGVkLi4uPiwgUDxBY2N1bXVsYXRlZC4uLiwgRmlyc3Q+PgoJPjo6dHlwZSB7fTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBULCB0ZW1wbGF0ZSA8VC4uLj4gY2xhc3MgUCwgVC4uLiBWaXNpdGVkLCBULi4uIEFjY3VtdWxhdGVkPgpzdHJ1Y3QgUmVtb3ZlVGhvc2VBbHJlYWR5VmlzaXRlZEhlbHBlcjxULCBQPD4sIFA8VmlzaXRlZC4uLj4sIFA8QWNjdW11bGF0ZWQuLi4+PiB7Cgl1c2luZyB0eXBlID0gUDxBY2N1bXVsYXRlZC4uLj47Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUsIHR5cGVuYW1lLCB0eXBlbmFtZT4gc3RydWN0IFJlbW92ZVRob3NlQWxyZWFkeVZpc2l0ZWQ7Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgdGVtcGxhdGUgPFQuLi4+IGNsYXNzIFAsIFQuLi4gVHMsIFQuLi4gVmlzaXRlZD4Kc3RydWN0IFJlbW92ZVRob3NlQWxyZWFkeVZpc2l0ZWQ8VCwgUDxUcy4uLj4sIFA8VmlzaXRlZC4uLj4+IDogUmVtb3ZlVGhvc2VBbHJlYWR5VmlzaXRlZEhlbHBlcjxULCBQPFRzLi4uPiwgUDxWaXNpdGVkLi4uPiwgUDw+PiB7fTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBULCB0ZW1wbGF0ZSA8VC4uLj4gY2xhc3MgUCwgVC4uLiBUcz4Kc3RydWN0IFJlbW92ZVRob3NlQWxyZWFkeVZpc2l0ZWQ8VCwgUDxUcy4uLj4sIFA8Pj4geyAgLy8gVGhlc2UgcmVtYWluaW5nIHNwZWNpYWxpemF0aW9ucyBhcmUgdG8gYXZvaWQgdXNpbmcgdGhlIGFib3ZlIHNwZWNpYWxpemF0aW9uIHNpbmNlICd0eXBlJyBpcyBpbW1lZGlhdGVseSBvYnZpb3VzIGFuZCBuZWVkcyBubyBjb21wdXRhdGlvbi4KCXVzaW5nIHR5cGUgPSBQPFRzLi4uPjsKfTsKCnRlbXBsYXRlIDx0eXBlbmFtZSBULCB0ZW1wbGF0ZSA8VC4uLj4gY2xhc3MgUCwgVC4uLiBWaXNpdGVkPgpzdHJ1Y3QgUmVtb3ZlVGhvc2VBbHJlYWR5VmlzaXRlZDxULCBQPD4sIFA8VmlzaXRlZC4uLj4+IHsKCXVzaW5nIHR5cGUgPSBQPD47Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgdGVtcGxhdGUgPFQuLi4+IGNsYXNzIFA+CnN0cnVjdCBSZW1vdmVUaG9zZUFscmVhZHlWaXNpdGVkPFQsIFA8PiwgUDw+PiB7ICAvLyBUaGlzIGlzIG5lZWRlZCB0byBhdm9pZCBhbWJpZ3VpdHkgd2l0aCB0aGUgYWJvdmUgdHdvIHNwZWNpYWxpemF0aW9ucy4KCXVzaW5nIHR5cGUgPSBQPD47Cn07CgovLyBOb3cgdGhlIG1haW4gc3RydWN0cy4KdGVtcGxhdGUgPHR5cGVuYW1lLCB0eXBlbmFtZSwgdHlwZW5hbWUsIHR5cGVuYW1lLCB0eXBlbmFtZT4gc3RydWN0IFRvcG9sb2dpY2FsU29ydDsKdGVtcGxhdGUgPHR5cGVuYW1lLCB0eXBlbmFtZSwgdHlwZW5hbWUsIHR5cGVuYW1lLCB0eXBlbmFtZSwgdHlwZW5hbWU+IHN0cnVjdCBUb3BvbG9naWNhbFNvcnRIZWxwZXI7CnRlbXBsYXRlIDx0eXBlbmFtZSwgdHlwZW5hbWUsIHR5cGVuYW1lLCB0eXBlbmFtZSwgdHlwZW5hbWUsIHR5cGVuYW1lPiBzdHJ1Y3QgVXBkYXRlU3RhY2s7CnRlbXBsYXRlIDx0eXBlbmFtZSwgdHlwZW5hbWUsIHR5cGVuYW1lLCB0eXBlbmFtZSwgdHlwZW5hbWU+IHN0cnVjdCBSZXR1cm5Ub1RvcG9sb2dpY2FsU29ydDsKCi8vIEVuZCBvZiB0aGUgdG9wb2xvZ2ljYWwgc29ydCBsb29wLiAgUmVwbGFjaW5nIFA8VmlzaXRlZC4uLj4gd2l0aCB0eXBlbmFtZSBWaXNpdGVkIGFuZC9vciBQPEVkZ2VzLi4uPiB3aXRoIHR5cGVuYW1lIEVkZ2VzIGFuZC9vciBQPFZlcnRpY2VzLi4uPiB3aXRoIHR5cGVuYW1lIFN0YWNrIHdpbGwgY2F1c2UgYW1iaWd1aXR5IGNvbXBpbGluZyBlcnJvciBzaW5jZSBuZWl0aGVyIHRoaXMgbm9yIHRoZSBhYm92ZSBwYXJ0aWFsIHNwZWNpYWxpemF0aW9uIGlzIG1vcmUgc3BlY2lhbGl6ZWQgdGhhbiB0aGUgb3RoZXIuIAp0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgdGVtcGxhdGUgPFQuLi4+IGNsYXNzIFAsIFQuLi4gVmlzaXRlZCwgVC4uLiBFZGdlcywgVC4uLiBWZXJ0aWNlcz4Kc3RydWN0IFRvcG9sb2dpY2FsU29ydDxULCBQPD4sIFA8RWRnZXMuLi4+LCBQPFZpc2l0ZWQuLi4+LCBQPFZlcnRpY2VzLi4uPj4gewoJdXNpbmcgdG9wb2xvZ2ljYWxfc29ydCA9IFA8VmVydGljZXMuLi4+OyAgLy8gVGhlIGZpbmFsIHN0YWNrIG9mIHZlcnRpY2VzIGRlc2NyaWJpbmcgYSB0b3BvbG9naWNhbCBvcmRlci4KCXVzaW5nIHZpc2l0ZWQgPSBQPFZpc2l0ZWQuLi4+OyAgLy8gVGhpcyBpcyBqdXN0IHRvIGNoZWNrIHRoYXQgUDxWaXNpdGVkLi4uPiBkb2VzIG5vdCBoYXZlIHJlcGVhdHMgKHRvIGVuc3VyZSBvcHRpbWFsIHBlcmZvcm1hbmNlKS4KfTsKCi8vIFRoZSB0b3BvbG9naWNhbCBzb3J0IGxvb3AuCnRlbXBsYXRlIDx0eXBlbmFtZSBULCB0ZW1wbGF0ZSA8VC4uLj4gY2xhc3MgUCwgVCBGaXJzdCwgVC4uLiBSZXN0LCBULi4uIFZpc2l0ZWQsIFQuLi4gRWRnZXMsIFQuLi4gVmVydGljZXM+ICAvLyBGaXJzdCwgUmVzdC4uLiBhcmUgdGhlIHZlcnRpY2VzIHRvIGJlIHZpc2l0ZWQgbm93IChpbiB0aGF0IG9yZGVyKS4Kc3RydWN0IFRvcG9sb2dpY2FsU29ydDxULCBQPEZpcnN0LCBSZXN0Li4uPiwgUDxFZGdlcy4uLj4sIFA8VmlzaXRlZC4uLj4sIFA8VmVydGljZXMuLi4+PiA6CglUb3BvbG9naWNhbFNvcnRIZWxwZXI8VCwgUDxGaXJzdCwgUmVzdC4uLj4sIFA8RWRnZXMuLi4+LCBQPFZpc2l0ZWQuLi4sIEZpcnN0PiwgUDxWZXJ0aWNlcy4uLj4sICAvLyBBcHBlbmQgRmlyc3QgdG8gUDxWaXNpdGVkLi4uPi4KCQkJdHlwZW5hbWUgUmVtb3ZlVGhvc2VBbHJlYWR5VmlzaXRlZDxULCB0eXBlbmFtZSBBZGphY2VudFZlcnRpY2VzPEZpcnN0LCBQPEVkZ2VzLi4uPj46OnR5cGUsIFA8VmlzaXRlZC4uLj4+Ojp0eXBlPiB7fTsgIC8vIFBhc3MgdGhlIGFkamFjZW50IHZlcnRpY2VzIG9mIEZpcnN0IChpZiBhbnkpLCBleGNlcHQgdGhvc2UgdGhhdCBoYXZlIGFscmVhZHkgYmVlbiB2aXNpdGVkLgoKLy8gVGhlIGZpcnN0IHR5cGUgaW4gVG9WaXNpdC4uLiBoYXMgYWRqYWNlbnQgZWRnZXMsIHNvIHZpc2l0IGl0cyBhZGphY2VudCB2ZXJ0aWNlcywgYW5kIHByZXBlbmQgdGhpcyBmaXJzdCB0eXBlIHRvIFA8VmVydGljZXMuLi4+IEFGVEVSIHRoZXNlIHZpc2l0cy4KdGVtcGxhdGUgPHR5cGVuYW1lIFQsIHRlbXBsYXRlIDxULi4uPiBjbGFzcyBQLCBULi4uIFRvVmlzaXQsIFQuLi4gVmlzaXRlZCwgVC4uLiBFZGdlcywgVC4uLiBWZXJ0aWNlcywgdHlwZW5hbWUgQWRqYWNlbnRWZXJ0aWNlcz4Kc3RydWN0IFRvcG9sb2dpY2FsU29ydEhlbHBlcjxULCBQPFRvVmlzaXQuLi4+LCBQPEVkZ2VzLi4uPiwgUDxWaXNpdGVkLi4uPiwgUDxWZXJ0aWNlcy4uLj4sIEFkamFjZW50VmVydGljZXM+IDoKCVVwZGF0ZVN0YWNrPFQsIFA8VG9WaXNpdC4uLj4sIFA8RWRnZXMuLi4+LCBQPFZpc2l0ZWQuLi4+LCBQPFZlcnRpY2VzLi4uPiwgVG9wb2xvZ2ljYWxTb3J0PFQsIEFkamFjZW50VmVydGljZXMsIFA8RWRnZXMuLi4+LCBQPFZpc2l0ZWQuLi4+LCBQPD4+PiB7fTsgIC8vIE11c3QgdXNlIFA8PiBpbnN0ZWFkIG9mIFA8VmVydGljZXMuLi4+IGhlcmUsIGJlY2F1c2Ugd2UgYXJlIGdvaW5nIHRvIGFkam9pbiB0aGUgdG9wb2xvZ2ljYWxfc29ydCBvZiB0aGlzIHBhcnRpY3VsYXIgc3VidHJlZSB0byBQPFZlcnRpY2VzLi4uPi4KCi8vIEZpcnN0IGhhcyBubyBhZGphY2VudCB2ZXJ0aWNlcywgc28gcHJlcGVuZCBpdCB0byBQPFZlcnRpY2VzLi4uPi4gIFNpbXBseSBwcmVwZW5kIEZpcnN0IHRvIFA8VmVydGljZXMuLi4+LCBhbmQgbW92ZSBvbiB0byBSZXN0Li4uCnRlbXBsYXRlIDx0eXBlbmFtZSBULCB0ZW1wbGF0ZSA8VC4uLj4gY2xhc3MgUCwgVCBGaXJzdCwgVC4uLiBSZXN0LCBULi4uIFZpc2l0ZWQsIFQuLi4gRWRnZXMsIFQuLi4gVmVydGljZXM+CnN0cnVjdCBUb3BvbG9naWNhbFNvcnRIZWxwZXI8VCwgUDxGaXJzdCwgUmVzdC4uLj4sIFA8RWRnZXMuLi4+LCBQPFZpc2l0ZWQuLi4+LCBQPFZlcnRpY2VzLi4uPiwgUDw+PiA6IFRvcG9sb2dpY2FsU29ydDxULCBQPFJlc3QuLi4+LCBQPEVkZ2VzLi4uPiwgUDxWaXNpdGVkLi4uPiwgUDxGaXJzdCwgVmVydGljZXMuLi4+PiB7fTsKCi8vIFVwZGF0aW5nIFA8VmVydGljZXMuLi4+IGFmdGVyIGFsbCBhZGphY2VudCAodW52aXNpdGVkKSBlZGdlcyBoYXZlIGJlZW4gdmlzaXRlZC4KdGVtcGxhdGUgPHR5cGVuYW1lIFQsIHRlbXBsYXRlIDxULi4uPiBjbGFzcyBQLCBUIEZpcnN0LCBULi4uIFJlc3QsIFQuLi4gVmlzaXRlZCwgVC4uLiBFZGdlcywgVC4uLiBWZXJ0aWNlcywgdHlwZW5hbWUgQWRqYWNlbnRFZGdlc1RvcG9sb2dpY2FsU29ydD4Kc3RydWN0IFVwZGF0ZVN0YWNrPFQsIFA8Rmlyc3QsIFJlc3QuLi4+LCBQPEVkZ2VzLi4uPiwgUDxWaXNpdGVkLi4uPiwgUDxWZXJ0aWNlcy4uLj4sIEFkamFjZW50RWRnZXNUb3BvbG9naWNhbFNvcnQ+IDoKCVJldHVyblRvVG9wb2xvZ2ljYWxTb3J0PFQsIFA8UmVzdC4uLj4sIFA8RWRnZXMuLi4+LAoJCXR5cGVuYW1lIFJlbW92ZUR1cGxpY2F0ZXM8VCwgdHlwZW5hbWUgTWVyZ2U8VCwgUDxWaXNpdGVkLi4uPiwgdHlwZW5hbWUgQWRqYWNlbnRFZGdlc1RvcG9sb2dpY2FsU29ydDo6dmlzaXRlZD46OnR5cGU+Ojp0eXBlLCAgLy8gUmVtb3ZlRHVwbGljYXRlcyBpcyBhY3R1YWxseSBub3QgbmVjZXNzYXJpbHkgKHRoZSByZXN1bHRzIGFyZSBzdGlsbCBjb3JyZWN0IHdpdGhvdXQgaXQpLCBidXQgd2l0aG91dCBpdCB0aGUgUDxWaXNpdGVkLi4uPiB3aWxsIGhhdmUgbWFueSBkdXBsaWNhdGVzIGluIGdlbmVyYWwgYW5kIHRodXMgbGVhZCB0byBzbG93ZXIgY29tcHV0YXRpb24gb2YgUmVtb3ZlVGhvc2VBbHJlYWR5VmlzaXRlZC4gCgkJdHlwZW5hbWUgTWVyZ2U8VCwgUDxGaXJzdD4sIHR5cGVuYW1lIEFkamFjZW50RWRnZXNUb3BvbG9naWNhbFNvcnQ6OnRvcG9sb2dpY2FsX3NvcnQsIFA8VmVydGljZXMuLi4+Pjo6dHlwZSAgLy8gV3JhcHBpbmcgdGhlIG1lcmdlIHJlc3VsdCB3aXRoIFJlbW92ZUR1cGxpY2F0ZXMgaXMgYXBwYXJlbnRseSBub3QgbmVjZXNzYXJ5LCBhcyBpdCBpcyBhcHBhcmVudGx5IG1hdGhlbWF0aWNhbGx5IGltcG9zc2libGUgZm9yIHRoZXJlIHRvIGJlIGR1cGxpY2F0ZXMgYWZ0ZXIgdGhpcyBtZXJnZS4KCT4ge307CgovLyBSZXR1cm4gdG8gVG9wb2xvZ2ljYWxTb3J0LCBidXQgZmlyc3QgcmVtb3ZlIGZyb20gVG9WaXNpdC4uLiBhbGwgdGhvc2UgdGhhdCBhcmUgaW4gVmlzaXRlZC4uLgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVCwgdGVtcGxhdGUgPFQuLi4+IGNsYXNzIFAsIFQuLi4gVG9WaXNpdCwgVC4uLiBWaXNpdGVkLCBULi4uIEVkZ2VzLCBULi4uIFZlcnRpY2VzPgpzdHJ1Y3QgUmV0dXJuVG9Ub3BvbG9naWNhbFNvcnQ8VCwgUDxUb1Zpc2l0Li4uPiwgUDxFZGdlcy4uLj4sIFA8VmlzaXRlZC4uLj4sIFA8VmVydGljZXMuLi4+PiA6CglUb3BvbG9naWNhbFNvcnQ8VCwgdHlwZW5hbWUgUmVtb3ZlVGhvc2VBbHJlYWR5VmlzaXRlZDxULCBQPFRvVmlzaXQuLi4+LCBQPFZpc2l0ZWQuLi4+Pjo6dHlwZSwgUDxFZGdlcy4uLj4sIFA8VmlzaXRlZC4uLj4sIFA8VmVydGljZXMuLi4+PiB7fTsgIC8vIFJlbW92ZVRob3NlQWxyZWFkeVZpc2l0ZWQgaXMgYWJzb2x1dGVseSBuZWNlc2FyeS4KCi8vIE5vdyB0aGUgR3JhcGggY2xhc3NlcyB0aGVtc2VsdmVzLgp0ZW1wbGF0ZSA8c3RkOjpzaXplX3QgTiwgc3RkOjpzaXplX3QuLi4gRWRnZXM+CnN0cnVjdCBHcmFwaDEgOiBUb3BvbG9naWNhbFNvcnQ8c3RkOjpzaXplX3QsIG1ha2VfaW5kZXhfc2VxdWVuY2U8Tj4sIGluZGV4X3NlcXVlbmNlPEVkZ2VzLi4uPiwgaW5kZXhfc2VxdWVuY2U8PiwgaW5kZXhfc2VxdWVuY2U8Pj4ge307CgovLyBTb3J0ZXIgY2xhc3MgbmVlZGVkIGZvciBjbGFzcyBHcmFwaDIsIHdoZXJlIHRoZSB2ZXJ0aWNlcyBjYW4gYmUgbm9uLWNvbnNlY3V0aXZlIGludGVnZXJzLCBhbmQgdGhlIG51bWJlciBvZiB2ZXJ0aWNlcyBkb2VzIG5vdCBuZWVkIHRvIGJlIHNwZWNpZmllZC4KdGVtcGxhdGUgPHN0ZDo6c2l6ZV90IEksIHN0ZDo6c2l6ZV90IEo+CnN0cnVjdCBJbnRMZXNzVGhhbiA6IHN0ZDo6Y29uZGl0aW9uYWw8KEkgPCBKKSwgc3RkOjp0cnVlX3R5cGUsIHN0ZDo6ZmFsc2VfdHlwZT46OnR5cGUge307Cgp0ZW1wbGF0ZSA8c3RkOjpzaXplX3QsIHR5cGVuYW1lPiBzdHJ1Y3QgUHJlcGVuZEludDsKCnRlbXBsYXRlIDxzdGQ6OnNpemVfdCBOLCB0ZW1wbGF0ZSA8c3RkOjpzaXplX3QuLi4+IGNsYXNzIFosIHN0ZDo6c2l6ZV90Li4uIElzPiAgCnN0cnVjdCBQcmVwZW5kSW50PE4sIFo8SXMuLi4+PiB7ICAKCXVzaW5nIHR5cGUgPSBaPE4sIElzLi4uPjsgIAp9OwoKdGVtcGxhdGUgPHRlbXBsYXRlPHN0ZDo6c2l6ZV90PiBjbGFzcywgdHlwZW5hbWU+IHN0cnVjdCBGaWx0ZXJJbnRzOyAgCgp0ZW1wbGF0ZSA8dGVtcGxhdGU8c3RkOjpzaXplX3Q+IGNsYXNzIEYsIHRlbXBsYXRlIDxzdGQ6OnNpemVfdC4uLj4gY2xhc3MgWiwgc3RkOjpzaXplX3QgSSwgc3RkOjpzaXplX3QuLi4gSXM+ICAKc3RydWN0IEZpbHRlckludHM8RiwgWjxJLCBJcy4uLj4+IHsKCXVzaW5nIHR5cGUgPSB0eXBlbmFtZSBzdGQ6OmNvbmRpdGlvbmFsPEY8ST46OnZhbHVlLAoJCXR5cGVuYW1lIFByZXBlbmRJbnQ8SSwgdHlwZW5hbWUgRmlsdGVySW50czxGLCBaPElzLi4uPj46OnR5cGU+Ojp0eXBlLAoJCXR5cGVuYW1lIEZpbHRlckludHM8RiwgWjxJcy4uLj4+Ojp0eXBlCgk+Ojp0eXBlOyAgCn07Cgp0ZW1wbGF0ZSA8dGVtcGxhdGU8c3RkOjpzaXplX3Q+IGNsYXNzIEYsIHRlbXBsYXRlIDxzdGQ6OnNpemVfdC4uLj4gY2xhc3MgWj4gIApzdHJ1Y3QgRmlsdGVySW50czxGLCBaPD4+IHsgIAoJdXNpbmcgdHlwZSA9IFo8PjsgIAp9OyAgCgp0ZW1wbGF0ZSA8dHlwZW5hbWUsIHR5cGVuYW1lPiBzdHJ1Y3QgTWVyZ2VJbnRTZXF1ZW5jZXM7ICAKCnRlbXBsYXRlIDx0ZW1wbGF0ZSA8c3RkOjpzaXplX3QuLi4+IGNsYXNzIFosIHN0ZDo6c2l6ZV90Li4uIElzLCBzdGQ6OnNpemVfdC4uLiBKcz4gIApzdHJ1Y3QgTWVyZ2VJbnRTZXF1ZW5jZXM8WjxJcy4uLj4sIFo8SnMuLi4+PiB7ICAKCXVzaW5nIHR5cGUgPSBaPElzLi4uLCBKcy4uLj47Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUsIHRlbXBsYXRlIDxzdGQ6OnNpemVfdCwgc3RkOjpzaXplX3Q+IGNsYXNzID0gSW50TGVzc1RoYW4+IHN0cnVjdCBTb3J0SW50U2VxdWVuY2U7ICAKCnRlbXBsYXRlIDx0ZW1wbGF0ZSA8c3RkOjpzaXplX3QuLi4+IGNsYXNzIFosIHN0ZDo6c2l6ZV90IE4sIHN0ZDo6c2l6ZV90Li4uIElzLCB0ZW1wbGF0ZSA8c3RkOjpzaXplX3QsIHN0ZDo6c2l6ZV90PiBjbGFzcyBDb21wYXJhdG9yPiAgCnN0cnVjdCBTb3J0SW50U2VxdWVuY2U8WjxOLCBJcy4uLj4sIENvbXBhcmF0b3I+IHsgIAoJdGVtcGxhdGU8c3RkOjpzaXplX3QgST4gc3RydWN0IGxlc3NfdGhhbiA6IHN0ZDo6aW50ZWdyYWxfY29uc3RhbnQ8Ym9vbCwgQ29tcGFyYXRvcjxJLE4+Ojp2YWx1ZT4ge307Cgl0ZW1wbGF0ZSA8c3RkOjpzaXplX3QgST4gc3RydWN0IG1vcmVfdGhhbiA6IHN0ZDo6aW50ZWdyYWxfY29uc3RhbnQ8Ym9vbCwgQ29tcGFyYXRvcjxOLEk+Ojp2YWx1ZSB8fCBJID09IE4+IHt9OyAgCgl1c2luZyBzdWJzZXF1ZW5jZV9sZXNzX3RoYW5fTiA9IHR5cGVuYW1lIEZpbHRlckludHM8bGVzc190aGFuLCBaPElzLi4uPj46OnR5cGU7Cgl1c2luZyBzdWJzZXF1ZW5jZV9tb3JlX3RoYW5fTiA9IHR5cGVuYW1lIEZpbHRlckludHM8bW9yZV90aGFuLCBaPElzLi4uPj46OnR5cGU7IAoJdXNpbmcgdHlwZSA9IHR5cGVuYW1lIE1lcmdlSW50U2VxdWVuY2VzPHR5cGVuYW1lIFNvcnRJbnRTZXF1ZW5jZTxzdWJzZXF1ZW5jZV9sZXNzX3RoYW5fTiwgQ29tcGFyYXRvcj46OnR5cGUsICAKCQl0eXBlbmFtZSBQcmVwZW5kSW50PE4sIHR5cGVuYW1lIFNvcnRJbnRTZXF1ZW5jZTxzdWJzZXF1ZW5jZV9tb3JlX3RoYW5fTiwgQ29tcGFyYXRvcj46OnR5cGU+Ojp0eXBlIAoJPjo6dHlwZTsKfTsKCnRlbXBsYXRlPHRlbXBsYXRlIDxzdGQ6OnNpemVfdC4uLj4gY2xhc3MgWiwgdGVtcGxhdGUgPHN0ZDo6c2l6ZV90LCBzdGQ6OnNpemVfdD4gY2xhc3MgQ29tcGFyYXRvcj4gIApzdHJ1Y3QgU29ydEludFNlcXVlbmNlPFo8PiwgQ29tcGFyYXRvcj4geyAgCgl1c2luZyB0eXBlID0gWjw+OyAgCn07CgovLyBHcmFwaDIgaXMgbW9yZSBmbGV4aWJsZSB0aGFuIEdyYXBoMSBiZWNhdXNlIHRoZSB2ZXJ0aWNlcyBjYW4gYmUgbm9uLWNvbnNlY3V0aXZlIGludGVnZXJzLCBhbmQgdGhlIG51bWJlciBvZiB2ZXJ0aWNlcyBkb2VzIG5vdCBuZWVkIHRvIGJlIHNwZWNpZmllZCBzaW5jZSB0aGF0IGNhbiBiZSBkZWR1Y2VkIGJ5IHRoZSB2ZXJ0aWNlcy4KdGVtcGxhdGUgPHN0ZDo6c2l6ZV90Li4uIEVkZ2VzPgpzdHJ1Y3QgR3JhcGgyIDogVG9wb2xvZ2ljYWxTb3J0PHN0ZDo6c2l6ZV90LCB0eXBlbmFtZSBTb3J0SW50U2VxdWVuY2U8dHlwZW5hbWUgUmVtb3ZlRHVwbGljYXRlczxzdGQ6OnNpemVfdCwgaW5kZXhfc2VxdWVuY2U8RWRnZXMuLi4+Pjo6dHlwZT46OnR5cGUsICAvLyBBbGwgZHVwbGljYXRlcyByZW1vdmVkLCBhbmQgdGhlIHZlcnRpY2VzIE1VU1QgYmUgc29ydGVkIGZvciB0aGlzIHRvIGNvbXBpbGUgKHRob3VnaCBJIGRpZG4ndCBib3RoZXIgdHJhY2luZyB3aHkpLiAgT2YgY291cnNlLCB0aGUgdmVydGljZXMgaW4gR3JhcGgxIGFyZSBhbHJlYWR5IHNvcnRlZC4KCWluZGV4X3NlcXVlbmNlPEVkZ2VzLi4uPiwgaW5kZXhfc2VxdWVuY2U8PiwgaW5kZXhfc2VxdWVuY2U8Pj4ge307CgovLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBUZXN0aW5nIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnRlbXBsYXRlIDxzdGQ6OnNpemVfdCBMYXN0PgpzdHJ1Y3QgaW5kZXhfc2VxdWVuY2U8TGFzdD4gewogICAgc3RhdGljIHZvaWQgcHJpbnQoKSB7c3RkOjpjb3V0IDw8IExhc3QgPDwgc3RkOjplbmRsO30KfTsKCnRlbXBsYXRlIDxzdGQ6OnNpemVfdCBGaXJzdCwgc3RkOjpzaXplX3QuLi4gUmVzdD4Kc3RydWN0IGluZGV4X3NlcXVlbmNlPEZpcnN0LCBSZXN0Li4uPiB7CiAgICBzdGF0aWMgdm9pZCBwcmludCgpIHtzdGQ6OmNvdXQgPDwgRmlyc3QgPDwgJyAnOyAgaW5kZXhfc2VxdWVuY2U8UmVzdC4uLj46OnByaW50KCk7fQp9OwoKaW50IG1haW4oKSB7Cgl1c2luZyBEQUcxID0gR3JhcGgxPDYsIDUsMiwgNSwwLCA0LDAsIDQsMSwgMiwzLCAzLDE+OwoJc3RkOjpjb3V0IDw8ICJUb3BvbG9naWNhbCBzb3J0IG9mIERBRzE6ICAiOyAgREFHMTo6dG9wb2xvZ2ljYWxfc29ydDo6cHJpbnQoKTsgIC8vIDUgNCAyIDMgMSAwICAoaWRlbnRpY2FsIHRvIHRoZSBydW4tdGltZSBzb2x1dGlvbiBhdCB0aGUgdG9wKQoJc3RkOjpjb3V0IDw8ICJWZXJ0aWNlcyB2aXNpdGVkIGluIERBRzE6ICAiOyAgREFHMTo6dmlzaXRlZDo6cHJpbnQoKTsgIC8vIDEgMiAzIDQgNSAobm8gcmVwZWF0cykKCXN0ZDo6Y291dCA8PCBzdGQ6OmJvb2xhbHBoYSA8PCBzdGQ6OmlzX3NhbWU8REFHMTo6dG9wb2xvZ2ljYWxfc29ydCwgaW5kZXhfc2VxdWVuY2U8NSw0LDIsMywxLDA+Pjo6dmFsdWUgPDwgc3RkOjplbmRsOyAgLy8gdHJ1ZQoKCXVzaW5nIERBRzIgPSBHcmFwaDE8OCwgMCwxLCAwLDIsIDAsMywgMSw0LCAxLDUsIDIsNCwgMiw2LCAzLDUsIDMsNiwgNCw3LCA1LDcsIDYsNz47CglzdGQ6OmNvdXQgPDwgIlxuVG9wb2xvZ2ljYWwgc29ydCBvZiBEQUcyOiAgIjsgIERBRzI6OnRvcG9sb2dpY2FsX3NvcnQ6OnByaW50KCk7ICAvLyAwIDMgMiA2IDEgNSA0IDcgIChpZGVudGljYWwgdG8gdGhlIHJ1bi10aW1lIHNvbHV0aW9uIGF0IHRoZSB0b3ApCglzdGQ6OmNvdXQgPDwgIlZlcnRpY2VzIHZpc2l0ZWQgaW4gREFHMjogICI7ICBEQUcyOjp2aXNpdGVkOjpwcmludCgpOyAgLy8gMCAxIDQgNyA1IDIgNiAzIChubyByZXBlYXRzKQoJc3RkOjpjb3V0IDw8IHN0ZDo6aXNfc2FtZTxEQUcyOjp0b3BvbG9naWNhbF9zb3J0LCBpbmRleF9zZXF1ZW5jZTwwLDMsMiw2LDEsNSw0LDc+Pjo6dmFsdWUgPDwgc3RkOjplbmRsOyAgLy8gdHJ1ZQoKCXVzaW5nIERBRzMgPSBHcmFwaDE8OCwgNSwxLCAxLDIsIDEsMCwgMSw2LCA3LDEsIDcsNCwgNCw2LCAzLDAsIDMsND47ICAvLyBUaGlzIGhhcyB0aGUgc2FtZSBlZGdlcyBhcyBEQUc1LCB3aXRoIDExIHJlbmFtZWQgdG8gMSwgMTAgcmVuYW1lZCB0byAwLCA5IHJlbmFtZWQgdG8gNiwgYW5kIDggcmVuYW1lZCB0byA0LgoJc3RkOjpjb3V0IDw8ICJcblRvcG9sb2dpY2FsIHNvcnQgb2YgREFHMzogICI7ICBEQUczOjp0b3BvbG9naWNhbF9zb3J0OjpwcmludCgpOyAgLy8gNyA1IDMgNCAxIDYgMiAwICAoaWRlbnRpY2FsIHRvIHRoZSBydW4tdGltZSBzb2x1dGlvbiBhdCB0aGUgdG9wKQoJc3RkOjpjb3V0IDw8ICJWZXJ0aWNlcyB2aXNpdGVkIGluIERBRzM6ICAiOyAgREFHMzo6dmlzaXRlZDo6cHJpbnQoKTsgIC8vIDAgMSAyIDYgMyA0IDUgNyAobm8gcmVwZWF0cykKCXN0ZDo6Y291dCA8PCBzdGQ6OmlzX3NhbWU8REFHMzo6dG9wb2xvZ2ljYWxfc29ydCwgaW5kZXhfc2VxdWVuY2U8Nyw1LDMsNCwxLDYsMiwwPj46OnZhbHVlIDw8IHN0ZDo6ZW5kbDsgIC8vIHRydWUKCglzdGQ6OmNvdXQgPDwgIlxuXG5Vc2luZyBHcmFwaDI6IiA8PCBzdGQ6OmVuZGw7Cgl1c2luZyBEQUc0ID0gR3JhcGgyPDAsMSwgMCwyLCAwLDMsIDEsNCwgMSw1LCAyLDQsIDIsNiwgMyw1LCAzLDYsIDQsNywgNSw3LCA2LDc+OwoJREFHNDo6dG9wb2xvZ2ljYWxfc29ydDo6cHJpbnQoKTsgIC8vIDAgMyAyIDYgMSA1IDQgNyAgKHNhbWUgc29sdXRpb24gYXMgREFHMiB1c2luZyB0aGUgR3JhcGgxIGNsYXNzKQoJc3RkOjpjb3V0IDw8IHN0ZDo6aXNfc2FtZTxEQUc0Ojp0b3BvbG9naWNhbF9zb3J0LCBpbmRleF9zZXF1ZW5jZTwwLDMsMiw2LDEsNSw0LDc+Pjo6dmFsdWUgPDwgc3RkOjplbmRsOyAgLy8gdHJ1ZQoKCXVzaW5nIERBRzUgPSBHcmFwaDI8NSwxMSwgMTEsMiwgMTEsMTAsIDExLDksIDcsMTEsIDcsOCwgOCw5LCAzLDEwLCAzLDg+OyAgLy8gU2VlIHRoZSBmaXJzdCBkaWFncmFtIGluIGh0dHA6Ly9lLi4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5hLm9yZy93aWtpL0RpcmVjdGVkX2FjeWNsaWNfZ3JhcGggZm9yIGEgcGljdHVyZSBvZiB0aGlzIGdyYXBoLgoJREFHNTo6dG9wb2xvZ2ljYWxfc29ydDo6cHJpbnQoKTsgIC8vIDcgNSAxMSAzIDggOSAxMCAyICAodGhpcyBpcyBpbmRlZWQgYSB2YWxpZCB0b3BvbG9naWNhbCBzb3J0KQoKCXVzaW5nIERBRzYgPSBHcmFwaDI8NSwxLCAxLDIsIDEsMCwgMSw2LCA3LDEsIDcsNCwgNCw2LCAzLDAsIDMsND47ICAvLyBUaGlzIEdyYXBoMiB0eXBlIGhhcyB0aGUgc2FtZSBlZGdlcyBhcyBEQUc1LCB3aXRoIDExIHJlbmFtZWQgdG8gMSwgMTAgcmVuYW1lZCB0byAwLCA5IHJlbmFtZWQgdG8gNiwgYW5kIDggcmVuYW1lZCB0byA0LgoJREFHNjo6dG9wb2xvZ2ljYWxfc29ydDo6cHJpbnQoKTsgIC8vIDcgNSAzIDQgMSA2IDIgMCAgKGlkZW50aWNhbCB0byB0aGUgcnVuLXRpbWUgc29sdXRpb24gYXQgdGhlIHRvcCkKCXN0ZDo6Y291dCA8PCBzdGQ6OmlzX3NhbWU8REFHNjo6dG9wb2xvZ2ljYWxfc29ydCwgaW5kZXhfc2VxdWVuY2U8Nyw1LDMsNCwxLDYsMiwwPj46OnZhbHVlIDw8IHN0ZDo6ZW5kbDsgIC8vIHRydWUKfQ==