// seems to work on https://i...content-available-to-author-only...r.edu/index.php?option=com_onlinejudge&Itemid=8&category=387&page=show_problem&problem=3091
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef string str;
typedef pair< int , int > pi;
typedef pair< ll,ll> pl;
typedef pair< ld,ld> pd;
#define mp make_pair
#define f first
#define s second
typedef vector< int > vi;
typedef vector< ll> vl;
typedef vector< ld> vd;
typedef vector< str> vs;
typedef vector< pi> vpi;
typedef vector< pl> vpl;
typedef vector< pd> vpd;
#define sz(x) (int)x.size()
#define all(x) begin(x), end(x)
#define rall(x) (x).rbegin(), (x).rend()
#define rsz resize
#define ins insert
#define ft front()
#define bk back()
#define pf push_front
#define pb push_back
#define eb emplace_back
#define lb lower_bound
#define ub upper_bound
#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i)
#define R0F(i,a) ROF(i,0,a)
#define trav(a,x) for (auto& a: x)
const int MOD = 1e9 + 7 ; // 998244353; // = (119<<23)+1
const int MX = 2e5 + 5 ;
const ll INF = 1e18 ;
const ld PI = 4 * atan ( ( ld) 1 ) ;
const int xd[ 4 ] = { 0 ,1 ,0 ,- 1 } , yd[ 4 ] = { 1 ,0 ,- 1 ,0 } ;
template < class T> bool ckmin( T& a, const T& b) {
return a > b ? a = b, 1 : 0 ; }
template < class T> bool ckmax( T& a, const T& b) {
return a < b ? a = b, 1 : 0 ; }
mt19937 rng( ( uint32_t ) chrono:: steady_clock :: now ( ) .time_since_epoch ( ) .count ( ) ) ;
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
template < class T> using Tree = tree< T, null_type, less< T> ,
rb_tree_tag, tree_order_statistics_node_update> ;
// change null_type for map
#define ook order_of_key
#define fbo find_by_order
void treeExample( ) {
Tree< int > t, t2; t.insert ( 8 ) ;
auto it = t.insert ( 10 ) .f ; assert ( it == t.lb ( 9 ) ) ;
assert ( t.ook ( 10 ) == 1 ) ; assert ( t.ook ( 11 ) == 2 ) ;
assert ( * t.fbo ( 0 ) == 8 ) ;
t.join ( t2) ; // assuming T < T2 or T > T2, merge t2 into t
}
namespace input {
template < class T> void re( complex< T> & x) ;
template < class T1, class T2> void re( pair< T1,T2> & p) ;
template < class T> void re( vector< T> & a) ;
template < class T, size_t SZ> void re( array< T,SZ> & a) ;
template < class T> void re( T& x) { cin >> x; }
void re( double & x) { string t; re( t) ; x = stod( t) ; }
void re( ld& x) { string t; re( t) ; x = stold( t) ; }
template < class T, class ... Ts > void re( T& t, Ts& ... ts ) {
re( t) ; re( ts...) ;
}
template < class T> void re( complex< T> & x) { T a,b; re( a,b) ; x = cd( a,b) ; }
template < class T1, class T2> void re( pair< T1,T2> & p) { re( p.f ,p.s ) ; }
template < class T> void re( vector< T> & a) { F0R( i,sz( a) ) re( a[ i] ) ; }
template < class T, size_t SZ> void re( array< T,SZ> & a) { F0R( i,SZ) re( a[ i] ) ; }
}
using namespace input;
namespace output {
void pr( int x) { cout << x; }
void pr( long x) { cout << x; }
void pr( ll x) { cout << x; }
void pr( unsigned x) { cout << x; }
void pr( unsigned long x) { cout << x; }
void pr( unsigned long long x) { cout << x; }
void pr( float x) { cout << x; }
void pr( double x) { cout << x; }
void pr( ld x) { cout << x; }
void pr( char x) { cout << x; }
void pr( const char * x) { cout << x; }
void pr( const string& x) { cout << x; }
void pr( bool x) { pr( x ? "true" : "false" ) ; }
template < class T> void pr( const complex< T> & x) { cout << x; }
template < class T1, class T2> void pr( const pair< T1,T2> & x) ;
template < class T> void pr( const T& x) ;
template < class T, class ... Ts > void pr( const T& t, const Ts& ... ts ) {
pr( t) ; pr( ts...) ;
}
template < class T1, class T2> void pr( const pair< T1,T2> & x) {
pr( "{" ,x.f ,", " ,x.s ,"}" ) ;
}
template < class T> void pr( const T& x) {
pr( "{" ) ; // const iterator needed for vector<bool>
bool fst = 1 ; for ( const auto & a: x) pr( ! fst? ", " : "" ,a) , fst = 0 ;
pr( "}" ) ;
}
void ps( ) { pr( "\n " ) ; } // print w/ spaces
template < class T, class ... Ts > void ps( const T& t, const Ts& ... ts ) {
pr( t) ; if ( sizeof ...( ts) ) pr( " " ) ; ps( ts...) ;
}
void pc( ) { pr( "]\n " ) ; } // debug w/ commas
template < class T, class ... Ts > void pc( const T& t, const Ts& ... ts ) {
pr( t) ; if ( sizeof ...( ts) ) pr( ", " ) ; pc( ts...) ;
}
#define dbg(x...) pr("[",#x,"] = ["), pc(x);
}
using namespace output;
namespace io {
void setIn( string s) { freopen ( s.c_str ( ) ,"r" ,stdin ) ; }
void setOut( string s) { freopen ( s.c_str ( ) ,"w" ,stdout ) ; }
void setIO( string s = "" ) {
ios_base:: sync_with_stdio ( 0 ) ; cin .tie ( 0 ) ; // fast I/O
// cin.exceptions(cin.failbit); // ex. throws exception when you try to read letter into int
if ( sz( s) ) { setIn( s+ ".in" ) , setOut( s+ ".out" ) ; } // for USACO
}
}
using namespace io;
struct mi {
typedef decay< decltype( MOD) > :: type T;
T val;
explicit operator T( ) const { return val; }
mi( ) { val = 0 ; }
mi( ll v) {
val = ( - MOD <= v && v <= MOD) ? v : v % MOD;
if ( val < 0 ) val + = MOD;
}
friend bool operator== ( const mi& a, const mi& b) {
return a.val == b.val ; }
friend bool operator! = ( const mi& a, const mi& b) {
return ! ( a == b) ; }
friend bool operator< ( const mi& a, const mi& b) {
return a.val < b.val ; }
friend void re( mi& a) { ll x; re( x) ; a = mi( x) ; }
friend void pr( const mi& a) { pr( a.val ) ; }
friend ostream& operator<< ( ostream& os, const mi& a) {
return os << a.val ; }
mi operator- ( ) const { return mi( - val) ; }
mi& operator+ = ( const mi& m) {
if ( ( val + = m.val ) >= MOD) val - = MOD;
return * this ; }
mi& operator- = ( const mi& m) {
if ( ( val - = m.val ) < 0 ) val + = MOD;
return * this ; }
mi& operator++ ( ) { return * this + = 1 ; }
mi& operator-- ( ) { return * this - = 1 ; }
friend mi operator+ ( mi a, const mi& b) { return a + = b; }
friend mi operator- ( mi a, const mi& b) { return a - = b; }
mi& operator* = ( const mi& m) {
val = ( ll) val* m.val % MOD; return * this ; }
friend mi pow ( mi a, ll p) {
mi ans = 1 ; assert ( p >= 0 ) ;
for ( ; p; p / = 2 , a * = a) if ( p& 1 ) ans * = a;
return ans;
}
friend mi inv( const mi& a) {
assert ( ! ( a == 0 ) ) ; return pow ( a,MOD- 2 ) ; }
mi& operator/ = ( const mi& m) { return ( * this ) * = inv( m) ; }
friend mi operator* ( mi a, const mi& b) { return a * = b; }
friend mi operator/ ( mi a, const mi& b) { return a / = b; }
} ;
typedef pair< mi,mi> pmi;
typedef vector< mi> vmi;
typedef vector< pmi> vpmi;
typedef ld T;
int sgn( T x) { return ( x> 0 ) - ( x< 0 ) ; }
T sq( T x) { return x* x; }
namespace Point3D {
typedef array< T,3 > P3;
typedef array< P3,3 > tri;
typedef vector< P3> vP3;
T norm( const P3& x) {
T sum = 0 ; F0R( i,sz( x) ) sum + = sq( x[ i] ) ;
return sum; }
T abs ( const P3& x) { return sqrt ( norm( x) ) ; }
P3& operator+ = ( P3& l, const P3& r) {
F0R( i,3 ) l[ i] + = r[ i] ;
return l; }
P3& operator- = ( P3& l, const P3& r) {
F0R( i,3 ) l[ i] - = r[ i] ;
return l; }
P3& operator* = ( P3& l, const T& r) {
F0R( i,3 ) l[ i] * = r;
return l; }
P3& operator/ = ( P3& l, const T& r) {
F0R( i,3 ) l[ i] / = r;
return l; }
P3 operator+ ( P3 l, const P3& r) { return l + = r; }
P3 operator- ( P3 l, const P3& r) { return l - = r; }
P3 operator* ( P3 l, const T& r) { return l * = r; }
P3 operator* ( const T& r, const P3& l) { return l* r; }
P3 operator/ ( P3 l, const T& r) { return l / = r; }
P3 unit( const P3& x) { return x/ abs ( x) ; }
T dot( const P3& a, const P3& b) {
T sum = 0 ; F0R( i,3 ) sum + = a[ i] * b[ i] ;
return sum; }
P3 cross( const P3& a, const P3& b) {
return { a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ] ,a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ] ,
a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] } ; }
P3 cross( const P3& a, const P3& b, const P3& c) {
return cross( b- a,c- a) ; }
P3 perp( const P3& a, const P3& b, const P3& c) {
return unit( cross( a,b,c) ) ; }
bool isMult( const P3& a, const P3& b) { // for long longs
P3 c = cross( a,b) ; F0R( i,sz( c) ) if ( c[ i] ! = 0 ) return 0 ;
return 1 ; }
bool collinear( const P3& a, const P3& b, const P3& c) {
return isMult( b- a,c- a) ; }
bool coplanar( const P3& a,const P3& b,const P3& c,const P3& d) {
return isMult( cross( b- a,c- a) ,cross( b- a,d- a) ) ; }
bool op( const P3& a, const P3& b) {
int ind = 0 ; // going in opposite directions?
FOR( i,1 ,3 ) if ( std:: abs ( a[ i] * b[ i] ) > std:: abs ( a[ ind] * b[ ind] ) )
ind = i;
return a[ ind] * b[ ind] < 0 ;
}
// coplanar points, b0 and b1 on opposite sides of a0-a1?
bool opSide( const P3& a,const P3& b,const P3& c,const P3& d) {
return op( cross( a,b,c) ,cross( a,b,d) ) ; }
// coplanar points, is a in triangle b
bool inTri( const P3& a, const tri& b) {
F0R( i,3 ) if ( opSide( b[ i] ,b[ ( i+ 1 ) % 3 ] ,b[ ( i+ 2 ) % 3 ] ,a) ) return 0 ;
return 1 ; }
// point-seg dist
T psDist( const P3& p,const P3& a,const P3& b) {
if ( dot( a- p,a- b) <= 0 ) return abs ( a- p) ;
if ( dot( b- p,b- a) <= 0 ) return abs ( b- p) ;
return abs ( cross( p,a,b) ) / abs ( a- b) ;
}
// projection onto line
P3 foot( const P3& p, const P3& a, const P3& b) {
P3 d = unit( b- a) ; return a+ dot( p- a,d) * d; }
// rotate p about axis
P3 rotAxis( const P3& p, const P3& a, const P3& b, T theta) {
P3 dz = unit( b- a) , f = foot( p,a,b) ;
P3 dx = p- f, dy = cross( dz,dx) ;
return f+ cos ( theta) * dx+ sin ( theta) * dy;
}
// projection onto plane
P3 foot( const P3& a, const tri& b) {
P3 c = perp( b[ 0 ] ,b[ 1 ] ,b[ 2 ] ) ;
return a- c* ( dot( a,c) - dot( b[ 0 ] ,c) ) ; }
// line-plane intersection
P3 lpIntersect( const P3& a0,const P3& a1,const tri& b) {
P3 c = unit( cross( b[ 2 ] - b[ 0 ] ,b[ 1 ] - b[ 0 ] ) ) ;
T x = dot( a0,c) - dot( b[ 0 ] ,c) , y = dot( a1,c) - dot( b[ 0 ] ,c) ;
return ( y* a0- x* a1) / ( y- x) ;
}
}
using namespace Point3D;
bool onSameHalfSpace( P3 a, P3 b, P3 p1, P3 p2, P3 p3) {
P3 hlp = cross( p2- p1,p3- p1) ;
return dot( hlp,a- p1) * dot( hlp,b- p1) >= 0 ;
}
map< array< int ,3 > ,int > hull;
void toggle( int i1, int i2, int i3, int ref) {
array< int ,3 > a = { i1,i2,i3} ;
if ( hull.count ( a) ) hull.erase ( a) ;
else hull[ a] = ref;
}
void makeHull( vP3& pts) {
FOR( i,1 ,sz( pts) ) if ( pts[ 0 ] ! = pts[ i] ) swap( pts[ 1 ] ,pts[ i] ) ;
FOR( i,2 ,sz( pts) ) if ( ! collinear( pts[ 0 ] ,pts[ 1 ] ,pts[ i] ) ) swap( pts[ 2 ] ,pts[ i] ) ;
FOR( i,3 ,sz( pts) ) if ( ! coplanar( pts[ 0 ] ,pts[ 1 ] ,pts[ 2 ] ,pts[ i] ) ) swap( pts[ 3 ] ,pts[ i] ) ;
hull[ { 0 ,1 ,2 } ] = 3 ; hull[ { 0 ,1 ,3 } ] = 2 ; hull[ { 0 ,2 ,3 } ] = 1 ; hull[ { 1 ,2 ,3 } ] = 0 ;
// ps("WUT",pts);
FOR( i,4 ,sz( pts) ) {
vector< pair< pair< int ,int > ,pair< int ,int >>> toChange;
trav( face,hull) {
int i1 = face.f [ 0 ] , i2 = face.f [ 1 ] , i3 = face.f [ 2 ] ;
P3 pt1 = pts[ i1] , pt2 = pts[ i2] , pt3 = pts[ i3] ;
P3 ref = pts[ face.s ] ;
if ( ! onSameHalfSpace( pts[ i] ,ref,pt1,pt2,pt3) ) {
toChange.pb ( { { i1,i2} ,{ i,i3} } ) ;
toChange.pb ( { { i1,i3} ,{ i,i2} } ) ;
toChange.pb ( { { i2,i3} ,{ i,i1} } ) ;
toChange.pb ( { { i1,i2} ,{ i3,i} } ) ;
}
}
trav( diff,toChange)
toggle( diff.f .f ,diff.f .s ,diff.s .f , diff.s .s ) ;
}
}
/*T signedPolyVolume(const vP3& p, const vector<F>& trilist) {
T v = 0;
trav(i,trilist) v += dot(cross(p[i.a],p[i.b]),p[i.c]);
return v/6;
}*/
int main( ) {
ios_base:: sync_with_stdio ( 0 ) ; cin .tie ( 0 ) ;
cout << fixed << setprecision( 4 ) ;
int N;
while ( cin >> N) {
hull.clear ( ) ;
vP3 v( N) ; re( v) ;
makeHull( v) ;
set< P3> faces;
ld vol = 0 , sa = 0 ;
trav( t,hull) {
auto T = t.f ;
if ( onSameHalfSpace( v[ T[ 0 ] ] + cross( v[ T[ 0 ] ] ,v[ T[ 1 ] ] ,v[ T[ 2 ] ] ) ,v[ t.s ] ,v[ T[ 0 ] ] ,v[ T[ 1 ] ] ,v[ T[ 2 ] ] ) )
swap( T[ 0 ] ,T[ 1 ] ) ;
faces.insert ( unit( cross( v[ T[ 0 ] ] ,v[ T[ 1 ] ] ,v[ T[ 2 ] ] ) ) ) ;
// vol += dot(cross(v[T[0]],v[T[1]]),v[T[2]]);
// sa += abs(cross(v[T[0]],v[T[1]],v[T[2]]));
//ps("FACE",v[T[0]],v[T[1]],v[T[2]]);
// ps("AH",v[T[0]],v[T[1]],v[T[2]],v[t.s]);
//ps(cross(v[T[0]],v[T[1]],v[T[2]]),v[t.s]);
}
// trav(t,faces) ps(t);
ps( sz( faces) ) ;
}
/*
vP3 v;
v.pb({0,0,0});
v.pb({1,0,0});
v.pb({0,1,0});
v.pb({0,0,1});
// F0R(i,8) v.pb(P3{i/4%2,i/2%2,i%2});
F0R(i,64) v.pb(P3{i/16%4,i/4%4,i%4});
random_shuffle(all(v));
makeHull(v);
*/
// you should actually read the stuff at the bottom
}
/* stuff you should look for
* int overflow, array bounds
* special cases (n=1?), slow multiset operations
* do smth instead of nothing and stay organized
*/
Ly8gc2VlbXMgdG8gd29yayBvbiBodHRwczovL2kuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLnIuZWR1L2luZGV4LnBocD9vcHRpb249Y29tX29ubGluZWp1ZGdlJkl0ZW1pZD04JmNhdGVnb3J5PTM4NyZwYWdlPXNob3dfcHJvYmxlbSZwcm9ibGVtPTMwOTEKCiNpbmNsdWRlIDxiaXRzL3N0ZGMrKy5oPgp1c2luZyBuYW1lc3BhY2Ugc3RkOwogCnR5cGVkZWYgbG9uZyBsb25nIGxsOwp0eXBlZGVmIGxvbmcgZG91YmxlIGxkOyAKdHlwZWRlZiBkb3VibGUgZGI7IAp0eXBlZGVmIHN0cmluZyBzdHI7IAoKdHlwZWRlZiBwYWlyPGludCwgaW50PiBwaTsKdHlwZWRlZiBwYWlyPGxsLGxsPiBwbDsgCnR5cGVkZWYgcGFpcjxsZCxsZD4gcGQ7IAojZGVmaW5lIG1wIG1ha2VfcGFpcgojZGVmaW5lIGYgZmlyc3QKI2RlZmluZSBzIHNlY29uZAoKdHlwZWRlZiB2ZWN0b3I8aW50PiB2aTsgCnR5cGVkZWYgdmVjdG9yPGxsPiB2bDsgCnR5cGVkZWYgdmVjdG9yPGxkPiB2ZDsgCnR5cGVkZWYgdmVjdG9yPHN0cj4gdnM7IAp0eXBlZGVmIHZlY3RvcjxwaT4gdnBpOyAKdHlwZWRlZiB2ZWN0b3I8cGw+IHZwbDsgCnR5cGVkZWYgdmVjdG9yPHBkPiB2cGQ7IAoKI2RlZmluZSBzeih4KSAoaW50KXguc2l6ZSgpCiNkZWZpbmUgYWxsKHgpIGJlZ2luKHgpLCBlbmQoeCkKI2RlZmluZSByYWxsKHgpICh4KS5yYmVnaW4oKSwgKHgpLnJlbmQoKSAKI2RlZmluZSByc3ogcmVzaXplCiNkZWZpbmUgaW5zIGluc2VydCAKI2RlZmluZSBmdCBmcm9udCgpIAojZGVmaW5lIGJrIGJhY2soKSAKI2RlZmluZSBwZiBwdXNoX2Zyb250IAojZGVmaW5lIHBiIHB1c2hfYmFjawojZGVmaW5lIGViIGVtcGxhY2VfYmFjayAKI2RlZmluZSBsYiBsb3dlcl9ib3VuZCAKI2RlZmluZSB1YiB1cHBlcl9ib3VuZCAKCiNkZWZpbmUgRk9SKGksYSxiKSBmb3IgKGludCBpID0gKGEpOyBpIDwgKGIpOyArK2kpCiNkZWZpbmUgRjBSKGksYSkgRk9SKGksMCxhKQojZGVmaW5lIFJPRihpLGEsYikgZm9yIChpbnQgaSA9IChiKS0xOyBpID49IChhKTsgLS1pKQojZGVmaW5lIFIwRihpLGEpIFJPRihpLDAsYSkKI2RlZmluZSB0cmF2KGEseCkgZm9yIChhdXRvJiBhOiB4KQoKY29uc3QgaW50IE1PRCA9IDFlOSs3OyAvLyA5OTgyNDQzNTM7IC8vID0gKDExOTw8MjMpKzEKY29uc3QgaW50IE1YID0gMmU1KzU7IApjb25zdCBsbCBJTkYgPSAxZTE4OyAKY29uc3QgbGQgUEkgPSA0KmF0YW4oKGxkKTEpOyAKY29uc3QgaW50IHhkWzRdID0gezAsMSwwLC0xfSwgeWRbNF0gPSB7MSwwLC0xLDB9OyAKCnRlbXBsYXRlPGNsYXNzIFQ+IGJvb2wgY2ttaW4oVCYgYSwgY29uc3QgVCYgYikgeyAKCXJldHVybiBhID4gYiA/IGEgPSBiLCAxIDogMDsgfQp0ZW1wbGF0ZTxjbGFzcyBUPiBib29sIGNrbWF4KFQmIGEsIGNvbnN0IFQmIGIpIHsgCglyZXR1cm4gYSA8IGIgPyBhID0gYiwgMSA6IDA7IH0KbXQxOTkzNyBybmcoKHVpbnQzMl90KWNocm9ubzo6c3RlYWR5X2Nsb2NrOjpub3coKS50aW1lX3NpbmNlX2Vwb2NoKCkuY291bnQoKSk7CgojaW5jbHVkZSA8ZXh0L3BiX2RzL3RyZWVfcG9saWN5LmhwcD4KI2luY2x1ZGUgPGV4dC9wYl9kcy9hc3NvY19jb250YWluZXIuaHBwPgp1c2luZyBuYW1lc3BhY2UgX19nbnVfcGJkczsKCnRlbXBsYXRlIDxjbGFzcyBUPiB1c2luZyBUcmVlID0gdHJlZTxULCBudWxsX3R5cGUsIGxlc3M8VD4sIAoJcmJfdHJlZV90YWcsIHRyZWVfb3JkZXJfc3RhdGlzdGljc19ub2RlX3VwZGF0ZT47IAovLyBjaGFuZ2UgbnVsbF90eXBlIGZvciBtYXAKI2RlZmluZSBvb2sgb3JkZXJfb2Zfa2V5CiNkZWZpbmUgZmJvIGZpbmRfYnlfb3JkZXIKCnZvaWQgdHJlZUV4YW1wbGUoKSB7CglUcmVlPGludD4gdCwgdDI7IHQuaW5zZXJ0KDgpOwoJYXV0byBpdCA9IHQuaW5zZXJ0KDEwKS5mOyBhc3NlcnQoaXQgPT0gdC5sYig5KSk7Cglhc3NlcnQodC5vb2soMTApID09IDEpOyBhc3NlcnQodC5vb2soMTEpID09IDIpOwoJYXNzZXJ0KCp0LmZibygwKSA9PSA4KTsKCXQuam9pbih0Mik7IC8vIGFzc3VtaW5nIFQgPCBUMiBvciBUID4gVDIsIG1lcmdlIHQyIGludG8gdAp9CgpuYW1lc3BhY2UgaW5wdXQgewoJdGVtcGxhdGU8Y2xhc3MgVD4gdm9pZCByZShjb21wbGV4PFQ+JiB4KTsKCXRlbXBsYXRlPGNsYXNzIFQxLCBjbGFzcyBUMj4gdm9pZCByZShwYWlyPFQxLFQyPiYgcCk7Cgl0ZW1wbGF0ZTxjbGFzcyBUPiB2b2lkIHJlKHZlY3RvcjxUPiYgYSk7Cgl0ZW1wbGF0ZTxjbGFzcyBULCBzaXplX3QgU1o+IHZvaWQgcmUoYXJyYXk8VCxTWj4mIGEpOwoKCXRlbXBsYXRlPGNsYXNzIFQ+IHZvaWQgcmUoVCYgeCkgeyBjaW4gPj4geDsgfQoJdm9pZCByZShkb3VibGUmIHgpIHsgc3RyaW5nIHQ7IHJlKHQpOyB4ID0gc3RvZCh0KTsgfQoJdm9pZCByZShsZCYgeCkgeyBzdHJpbmcgdDsgcmUodCk7IHggPSBzdG9sZCh0KTsgfQoJdGVtcGxhdGU8Y2xhc3MgVCwgY2xhc3MuLi4gVHM+IHZvaWQgcmUoVCYgdCwgVHMmLi4uIHRzKSB7IAoJCXJlKHQpOyByZSh0cy4uLik7IAoJfQoKCXRlbXBsYXRlPGNsYXNzIFQ+IHZvaWQgcmUoY29tcGxleDxUPiYgeCkgeyBUIGEsYjsgcmUoYSxiKTsgeCA9IGNkKGEsYik7IH0KCXRlbXBsYXRlPGNsYXNzIFQxLCBjbGFzcyBUMj4gdm9pZCByZShwYWlyPFQxLFQyPiYgcCkgeyByZShwLmYscC5zKTsgfQoJdGVtcGxhdGU8Y2xhc3MgVD4gdm9pZCByZSh2ZWN0b3I8VD4mIGEpIHsgRjBSKGksc3ooYSkpIHJlKGFbaV0pOyB9Cgl0ZW1wbGF0ZTxjbGFzcyBULCBzaXplX3QgU1o+IHZvaWQgcmUoYXJyYXk8VCxTWj4mIGEpIHsgRjBSKGksU1opIHJlKGFbaV0pOyB9Cn0KCnVzaW5nIG5hbWVzcGFjZSBpbnB1dDsKCm5hbWVzcGFjZSBvdXRwdXQgewoJdm9pZCBwcihpbnQgeCkgeyBjb3V0IDw8IHg7IH0KCXZvaWQgcHIobG9uZyB4KSB7IGNvdXQgPDwgeDsgfQoJdm9pZCBwcihsbCB4KSB7IGNvdXQgPDwgeDsgfQoJdm9pZCBwcih1bnNpZ25lZCB4KSB7IGNvdXQgPDwgeDsgfQoJdm9pZCBwcih1bnNpZ25lZCBsb25nIHgpIHsgY291dCA8PCB4OyB9Cgl2b2lkIHByKHVuc2lnbmVkIGxvbmcgbG9uZyB4KSB7IGNvdXQgPDwgeDsgfQoJdm9pZCBwcihmbG9hdCB4KSB7IGNvdXQgPDwgeDsgfQoJdm9pZCBwcihkb3VibGUgeCkgeyBjb3V0IDw8IHg7IH0KCXZvaWQgcHIobGQgeCkgeyBjb3V0IDw8IHg7IH0KCXZvaWQgcHIoY2hhciB4KSB7IGNvdXQgPDwgeDsgfQoJdm9pZCBwcihjb25zdCBjaGFyKiB4KSB7IGNvdXQgPDwgeDsgfQoJdm9pZCBwcihjb25zdCBzdHJpbmcmIHgpIHsgY291dCA8PCB4OyB9Cgl2b2lkIHByKGJvb2wgeCkgeyBwcih4ID8gInRydWUiIDogImZhbHNlIik7IH0KCXRlbXBsYXRlPGNsYXNzIFQ+IHZvaWQgcHIoY29uc3QgY29tcGxleDxUPiYgeCkgeyBjb3V0IDw8IHg7IH0KCQoJdGVtcGxhdGU8Y2xhc3MgVDEsIGNsYXNzIFQyPiB2b2lkIHByKGNvbnN0IHBhaXI8VDEsVDI+JiB4KTsKCXRlbXBsYXRlPGNsYXNzIFQ+IHZvaWQgcHIoY29uc3QgVCYgeCk7CgkKCXRlbXBsYXRlPGNsYXNzIFQsIGNsYXNzLi4uIFRzPiB2b2lkIHByKGNvbnN0IFQmIHQsIGNvbnN0IFRzJi4uLiB0cykgeyAKCQlwcih0KTsgcHIodHMuLi4pOyAKCX0KCXRlbXBsYXRlPGNsYXNzIFQxLCBjbGFzcyBUMj4gdm9pZCBwcihjb25zdCBwYWlyPFQxLFQyPiYgeCkgeyAKCQlwcigieyIseC5mLCIsICIseC5zLCJ9Iik7IAoJfQoJdGVtcGxhdGU8Y2xhc3MgVD4gdm9pZCBwcihjb25zdCBUJiB4KSB7IAoJCXByKCJ7Iik7IC8vIGNvbnN0IGl0ZXJhdG9yIG5lZWRlZCBmb3IgdmVjdG9yPGJvb2w+CgkJYm9vbCBmc3QgPSAxOyBmb3IgKGNvbnN0IGF1dG8mIGE6IHgpIHByKCFmc3Q/IiwgIjoiIixhKSwgZnN0ID0gMDsgCgkJcHIoIn0iKTsKCX0KCQoJdm9pZCBwcygpIHsgcHIoIlxuIik7IH0gLy8gcHJpbnQgdy8gc3BhY2VzCgl0ZW1wbGF0ZTxjbGFzcyBULCBjbGFzcy4uLiBUcz4gdm9pZCBwcyhjb25zdCBUJiB0LCBjb25zdCBUcyYuLi4gdHMpIHsgCgkJcHIodCk7IGlmIChzaXplb2YuLi4odHMpKSBwcigiICIpOyBwcyh0cy4uLik7IAoJfQoJCgl2b2lkIHBjKCkgeyBwcigiXVxuIik7IH0gLy8gZGVidWcgdy8gY29tbWFzCgl0ZW1wbGF0ZTxjbGFzcyBULCBjbGFzcy4uLiBUcz4gdm9pZCBwYyhjb25zdCBUJiB0LCBjb25zdCBUcyYuLi4gdHMpIHsgCgkJcHIodCk7IGlmIChzaXplb2YuLi4odHMpKSBwcigiLCAiKTsgcGModHMuLi4pOyAKCX0KCSNkZWZpbmUgZGJnKHguLi4pIHByKCJbIiwjeCwiXSA9IFsiKSwgcGMoeCk7Cn0KCnVzaW5nIG5hbWVzcGFjZSBvdXRwdXQ7CgpuYW1lc3BhY2UgaW8gewoJdm9pZCBzZXRJbihzdHJpbmcgcykgeyBmcmVvcGVuKHMuY19zdHIoKSwiciIsc3RkaW4pOyB9Cgl2b2lkIHNldE91dChzdHJpbmcgcykgeyBmcmVvcGVuKHMuY19zdHIoKSwidyIsc3Rkb3V0KTsgfQoJdm9pZCBzZXRJTyhzdHJpbmcgcyA9ICIiKSB7CgkJaW9zX2Jhc2U6OnN5bmNfd2l0aF9zdGRpbygwKTsgY2luLnRpZSgwKTsgLy8gZmFzdCBJL08KCQkvLyBjaW4uZXhjZXB0aW9ucyhjaW4uZmFpbGJpdCk7IC8vIGV4LiB0aHJvd3MgZXhjZXB0aW9uIHdoZW4geW91IHRyeSB0byByZWFkIGxldHRlciBpbnRvIGludAoJCWlmIChzeihzKSkgeyBzZXRJbihzKyIuaW4iKSwgc2V0T3V0KHMrIi5vdXQiKTsgfSAvLyBmb3IgVVNBQ08KCX0KfQoKdXNpbmcgbmFtZXNwYWNlIGlvOwoKc3RydWN0IG1pIHsKCXR5cGVkZWYgZGVjYXk8ZGVjbHR5cGUoTU9EKT46OnR5cGUgVDsKCVQgdmFsOyAKCWV4cGxpY2l0IG9wZXJhdG9yIFQoKSBjb25zdCB7IHJldHVybiB2YWw7IH0KCW1pKCkgeyB2YWwgPSAwOyB9CgltaShsbCB2KSB7IAoJCXZhbCA9ICgtTU9EIDw9IHYgJiYgdiA8PSBNT0QpID8gdiA6IHYgJSBNT0Q7CgkJaWYgKHZhbCA8IDApIHZhbCArPSBNT0Q7Cgl9CglmcmllbmQgYm9vbCBvcGVyYXRvcj09KGNvbnN0IG1pJiBhLCBjb25zdCBtaSYgYikgeyAKCQlyZXR1cm4gYS52YWwgPT0gYi52YWw7IH0KCWZyaWVuZCBib29sIG9wZXJhdG9yIT0oY29uc3QgbWkmIGEsIGNvbnN0IG1pJiBiKSB7IAoJCXJldHVybiAhKGEgPT0gYik7IH0KCWZyaWVuZCBib29sIG9wZXJhdG9yPChjb25zdCBtaSYgYSwgY29uc3QgbWkmIGIpIHsgCgkJcmV0dXJuIGEudmFsIDwgYi52YWw7IH0KCWZyaWVuZCB2b2lkIHJlKG1pJiBhKSB7IGxsIHg7IHJlKHgpOyBhID0gbWkoeCk7IH0KCWZyaWVuZCB2b2lkIHByKGNvbnN0IG1pJiBhKSB7IHByKGEudmFsKTsgfQoJZnJpZW5kIG9zdHJlYW0mIG9wZXJhdG9yPDwob3N0cmVhbSYgb3MsIGNvbnN0IG1pJiBhKSB7IAoJCXJldHVybiBvcyA8PCBhLnZhbDsgfQogICAKCW1pIG9wZXJhdG9yLSgpIGNvbnN0IHsgcmV0dXJuIG1pKC12YWwpOyB9CgltaSYgb3BlcmF0b3IrPShjb25zdCBtaSYgbSkgeyAKCQlpZiAoKHZhbCArPSBtLnZhbCkgPj0gTU9EKSB2YWwgLT0gTU9EOyAKCQlyZXR1cm4gKnRoaXM7IH0KCW1pJiBvcGVyYXRvci09KGNvbnN0IG1pJiBtKSB7IAoJCWlmICgodmFsIC09IG0udmFsKSA8IDApIHZhbCArPSBNT0Q7IAoJCXJldHVybiAqdGhpczsgfQoJbWkmIG9wZXJhdG9yKysoKSB7IHJldHVybiAqdGhpcyArPSAxOyB9CgltaSYgb3BlcmF0b3ItLSgpIHsgcmV0dXJuICp0aGlzIC09IDE7IH0KCWZyaWVuZCBtaSBvcGVyYXRvcisobWkgYSwgY29uc3QgbWkmIGIpIHsgcmV0dXJuIGEgKz0gYjsgfQoJZnJpZW5kIG1pIG9wZXJhdG9yLShtaSBhLCBjb25zdCBtaSYgYikgeyByZXR1cm4gYSAtPSBiOyB9CgoJbWkmIG9wZXJhdG9yKj0oY29uc3QgbWkmIG0pIHsgCgkJdmFsID0gKGxsKXZhbCptLnZhbCVNT0Q7IHJldHVybiAqdGhpczsgfQoJZnJpZW5kIG1pIHBvdyhtaSBhLCBsbCBwKSB7CgkJbWkgYW5zID0gMTsgYXNzZXJ0KHAgPj0gMCk7CgkJZm9yICg7IHA7IHAgLz0gMiwgYSAqPSBhKSBpZiAocCYxKSBhbnMgKj0gYTsKCQlyZXR1cm4gYW5zOwoJfQoJZnJpZW5kIG1pIGludihjb25zdCBtaSYgYSkgeyAKCQlhc3NlcnQoIShhID09IDApKTsgcmV0dXJuIHBvdyhhLE1PRC0yKTsgfQoJbWkmIG9wZXJhdG9yLz0oY29uc3QgbWkmIG0pIHsgcmV0dXJuICgqdGhpcykgKj0gaW52KG0pOyB9CglmcmllbmQgbWkgb3BlcmF0b3IqKG1pIGEsIGNvbnN0IG1pJiBiKSB7IHJldHVybiBhICo9IGI7IH0KCWZyaWVuZCBtaSBvcGVyYXRvci8obWkgYSwgY29uc3QgbWkmIGIpIHsgcmV0dXJuIGEgLz0gYjsgfQp9Owp0eXBlZGVmIHBhaXI8bWksbWk+IHBtaTsKdHlwZWRlZiB2ZWN0b3I8bWk+IHZtaTsKdHlwZWRlZiB2ZWN0b3I8cG1pPiB2cG1pOwoKdHlwZWRlZiBsZCBUOwppbnQgc2duKFQgeCkgeyByZXR1cm4gKHg+MCktKHg8MCk7IH0KVCBzcShUIHgpIHsgcmV0dXJuIHgqeDsgfQoKbmFtZXNwYWNlIFBvaW50M0QgewoJdHlwZWRlZiBhcnJheTxULDM+IFAzOwoJdHlwZWRlZiBhcnJheTxQMywzPiB0cmk7Cgl0eXBlZGVmIHZlY3RvcjxQMz4gdlAzOwoJVCBub3JtKGNvbnN0IFAzJiB4KSB7IAoJCVQgc3VtID0gMDsgRjBSKGksc3ooeCkpIHN1bSArPSBzcSh4W2ldKTsKCQlyZXR1cm4gc3VtOyB9CglUIGFicyhjb25zdCBQMyYgeCkgeyByZXR1cm4gc3FydChub3JtKHgpKTsgfQoJCglQMyYgb3BlcmF0b3IrPShQMyYgbCwgY29uc3QgUDMmIHIpIHsgCgkJRjBSKGksMykgbFtpXSArPSByW2ldOyAKCQlyZXR1cm4gbDsgfQoJUDMmIG9wZXJhdG9yLT0oUDMmIGwsIGNvbnN0IFAzJiByKSB7IAoJCUYwUihpLDMpIGxbaV0gLT0gcltpXTsgCgkJcmV0dXJuIGw7IH0KCVAzJiBvcGVyYXRvcio9KFAzJiBsLCBjb25zdCBUJiByKSB7IAoJCUYwUihpLDMpIGxbaV0gKj0gcjsgCgkJcmV0dXJuIGw7IH0KCVAzJiBvcGVyYXRvci89KFAzJiBsLCBjb25zdCBUJiByKSB7IAoJCUYwUihpLDMpIGxbaV0gLz0gcjsgCgkJcmV0dXJuIGw7IH0KCVAzIG9wZXJhdG9yKyhQMyBsLCBjb25zdCBQMyYgcikgeyByZXR1cm4gbCArPSByOyB9CglQMyBvcGVyYXRvci0oUDMgbCwgY29uc3QgUDMmIHIpIHsgcmV0dXJuIGwgLT0gcjsgfQoJUDMgb3BlcmF0b3IqKFAzIGwsIGNvbnN0IFQmIHIpIHsgcmV0dXJuIGwgKj0gcjsgfQoJUDMgb3BlcmF0b3IqKGNvbnN0IFQmIHIsIGNvbnN0IFAzJiBsKSB7IHJldHVybiBsKnI7IH0KCVAzIG9wZXJhdG9yLyhQMyBsLCBjb25zdCBUJiByKSB7IHJldHVybiBsIC89IHI7IH0KCQoJUDMgdW5pdChjb25zdCBQMyYgeCkgeyByZXR1cm4geC9hYnMoeCk7IH0KCVQgZG90KGNvbnN0IFAzJiBhLCBjb25zdCBQMyYgYikgeyAKCQlUIHN1bSA9IDA7IEYwUihpLDMpIHN1bSArPSBhW2ldKmJbaV07IAoJCXJldHVybiBzdW07IH0KCVAzIGNyb3NzKGNvbnN0IFAzJiBhLCBjb25zdCBQMyYgYikgewoJCXJldHVybiB7YVsxXSpiWzJdLWFbMl0qYlsxXSxhWzJdKmJbMF0tYVswXSpiWzJdLAoJCQkJYVswXSpiWzFdLWFbMV0qYlswXX07IH0KCVAzIGNyb3NzKGNvbnN0IFAzJiBhLCBjb25zdCBQMyYgYiwgY29uc3QgUDMmIGMpIHsKCQlyZXR1cm4gY3Jvc3MoYi1hLGMtYSk7IH0KCVAzIHBlcnAoY29uc3QgUDMmIGEsIGNvbnN0IFAzJiBiLCBjb25zdCBQMyYgYykgewoJCXJldHVybiB1bml0KGNyb3NzKGEsYixjKSk7IH0KCglib29sIGlzTXVsdChjb25zdCBQMyYgYSwgY29uc3QgUDMmIGIpIHsgLy8gZm9yIGxvbmcgbG9uZ3MKCQlQMyBjID0gY3Jvc3MoYSxiKTsgRjBSKGksc3ooYykpIGlmIChjW2ldICE9IDApIHJldHVybiAwOyAKCQlyZXR1cm4gMTsgfQoJYm9vbCBjb2xsaW5lYXIoY29uc3QgUDMmIGEsIGNvbnN0IFAzJiBiLCBjb25zdCBQMyYgYykgeyAKCQlyZXR1cm4gaXNNdWx0KGItYSxjLWEpOyB9Cglib29sIGNvcGxhbmFyKGNvbnN0IFAzJmEsY29uc3QgUDMmYixjb25zdCBQMyZjLGNvbnN0IFAzJmQpIHsgCgkJcmV0dXJuIGlzTXVsdChjcm9zcyhiLWEsYy1hKSxjcm9zcyhiLWEsZC1hKSk7IH0KCWJvb2wgb3AoY29uc3QgUDMmIGEsIGNvbnN0IFAzJiBiKSB7IAoJCWludCBpbmQgPSAwOyAvLyBnb2luZyBpbiBvcHBvc2l0ZSBkaXJlY3Rpb25zPwoJCUZPUihpLDEsMykgaWYgKHN0ZDo6YWJzKGFbaV0qYltpXSk+c3RkOjphYnMoYVtpbmRdKmJbaW5kXSkpIAoJCQlpbmQgPSBpOwoJCXJldHVybiBhW2luZF0qYltpbmRdIDwgMDsKCX0KCS8vIGNvcGxhbmFyIHBvaW50cywgYjAgYW5kIGIxIG9uIG9wcG9zaXRlIHNpZGVzIG9mIGEwLWExPwoJYm9vbCBvcFNpZGUoY29uc3QgUDMmYSxjb25zdCBQMyZiLGNvbnN0IFAzJmMsY29uc3QgUDMmZCkgeyAKCQlyZXR1cm4gb3AoY3Jvc3MoYSxiLGMpLGNyb3NzKGEsYixkKSk7IH0KCS8vIGNvcGxhbmFyIHBvaW50cywgaXMgYSBpbiB0cmlhbmdsZSBiCglib29sIGluVHJpKGNvbnN0IFAzJiBhLCBjb25zdCB0cmkmIGIpIHsgCgkJRjBSKGksMylpZihvcFNpZGUoYltpXSxiWyhpKzEpJTNdLGJbKGkrMiklM10sYSkpcmV0dXJuIDA7CgkJcmV0dXJuIDE7IH0KCgkvLyBwb2ludC1zZWcgZGlzdAoJVCBwc0Rpc3QoY29uc3QgUDMmcCxjb25zdCBQMyZhLGNvbnN0IFAzJmIpIHsgCgkJaWYgKGRvdChhLXAsYS1iKSA8PSAwKSByZXR1cm4gYWJzKGEtcCk7CgkJaWYgKGRvdChiLXAsYi1hKSA8PSAwKSByZXR1cm4gYWJzKGItcCk7CgkJcmV0dXJuIGFicyhjcm9zcyhwLGEsYikpL2FicyhhLWIpOwoJfQoJLy8gcHJvamVjdGlvbiBvbnRvIGxpbmUKCVAzIGZvb3QoY29uc3QgUDMmIHAsIGNvbnN0IFAzJiBhLCBjb25zdCBQMyYgYikgeyAKCQlQMyBkID0gdW5pdChiLWEpOyByZXR1cm4gYStkb3QocC1hLGQpKmQ7IH0KCS8vIHJvdGF0ZSBwIGFib3V0IGF4aXMKCVAzIHJvdEF4aXMoY29uc3QgUDMmIHAsIGNvbnN0IFAzJiBhLCBjb25zdCBQMyYgYiwgVCB0aGV0YSkgewoJCVAzIGR6ID0gdW5pdChiLWEpLCBmID0gZm9vdChwLGEsYik7IAoJCVAzIGR4ID0gcC1mLCBkeSA9IGNyb3NzKGR6LGR4KTsKCQlyZXR1cm4gZitjb3ModGhldGEpKmR4K3Npbih0aGV0YSkqZHk7Cgl9CgkvLyBwcm9qZWN0aW9uIG9udG8gcGxhbmUKCVAzIGZvb3QoY29uc3QgUDMmIGEsIGNvbnN0IHRyaSYgYikgewoJCVAzIGMgPSBwZXJwKGJbMF0sYlsxXSxiWzJdKTsKCQlyZXR1cm4gYS1jKihkb3QoYSxjKS1kb3QoYlswXSxjKSk7IH0KCS8vIGxpbmUtcGxhbmUgaW50ZXJzZWN0aW9uCglQMyBscEludGVyc2VjdChjb25zdCBQMyZhMCxjb25zdCBQMyZhMSxjb25zdCB0cmkmYikgeyAKCQlQMyBjID0gdW5pdChjcm9zcyhiWzJdLWJbMF0sYlsxXS1iWzBdKSk7CgkJVCB4ID0gZG90KGEwLGMpLWRvdChiWzBdLGMpLCB5ID0gZG90KGExLGMpLWRvdChiWzBdLGMpOwoJCXJldHVybiAoeSphMC14KmExKS8oeS14KTsKCX0KfQp1c2luZyBuYW1lc3BhY2UgUG9pbnQzRDsKCmJvb2wgb25TYW1lSGFsZlNwYWNlKFAzIGEsIFAzIGIsIFAzIHAxLCBQMyBwMiwgUDMgcDMpIHsKCVAzIGhscCA9IGNyb3NzKHAyLXAxLHAzLXAxKTsKCXJldHVybiBkb3QoaGxwLGEtcDEpKmRvdChobHAsYi1wMSkgPj0gMDsKfQptYXA8YXJyYXk8aW50LDM+LGludD4gaHVsbDsKdm9pZCB0b2dnbGUoaW50IGkxLCBpbnQgaTIsIGludCBpMywgaW50IHJlZikgewoJYXJyYXk8aW50LDM+IGEgPSB7aTEsaTIsaTN9OwoJaWYgKGh1bGwuY291bnQoYSkpIGh1bGwuZXJhc2UoYSk7CgllbHNlIGh1bGxbYV0gPSByZWY7Cn0KCnZvaWQgbWFrZUh1bGwodlAzJiBwdHMpIHsKCUZPUihpLDEsc3oocHRzKSkgaWYgKHB0c1swXSAhPSBwdHNbaV0pIHN3YXAocHRzWzFdLHB0c1tpXSk7IAoJRk9SKGksMixzeihwdHMpKSBpZiAoIWNvbGxpbmVhcihwdHNbMF0scHRzWzFdLHB0c1tpXSkpIHN3YXAocHRzWzJdLHB0c1tpXSk7IAoJRk9SKGksMyxzeihwdHMpKSBpZiAoIWNvcGxhbmFyKHB0c1swXSxwdHNbMV0scHRzWzJdLHB0c1tpXSkpIHN3YXAocHRzWzNdLHB0c1tpXSk7IAoJaHVsbFt7MCwxLDJ9XT0zOyBodWxsW3swLDEsM31dPTI7IGh1bGxbezAsMiwzfV09MTsgaHVsbFt7MSwyLDN9XT0wOwoJCgkvLyBwcygiV1VUIixwdHMpOwoJRk9SKGksNCxzeihwdHMpKSB7CgkJdmVjdG9yPHBhaXI8cGFpcjxpbnQsaW50PixwYWlyPGludCxpbnQ+Pj4gdG9DaGFuZ2U7CgkJdHJhdihmYWNlLGh1bGwpIHsKCQkJaW50IGkxID0gZmFjZS5mWzBdLCBpMiA9IGZhY2UuZlsxXSwgaTMgPSBmYWNlLmZbMl07CgkJCVAzIHB0MSA9IHB0c1tpMV0sIHB0MiA9IHB0c1tpMl0sIHB0MyA9IHB0c1tpM107CgkJCVAzIHJlZiA9IHB0c1tmYWNlLnNdOwoJCQlpZiAoIW9uU2FtZUhhbGZTcGFjZShwdHNbaV0scmVmLHB0MSxwdDIscHQzKSkgewoJCQkJdG9DaGFuZ2UucGIoe3tpMSxpMn0se2ksaTN9fSk7CgkJCQl0b0NoYW5nZS5wYih7e2kxLGkzfSx7aSxpMn19KTsKCQkJCXRvQ2hhbmdlLnBiKHt7aTIsaTN9LHtpLGkxfX0pOwoJCQkJdG9DaGFuZ2UucGIoe3tpMSxpMn0se2kzLGl9fSk7CgkJCX0KCQl9CgkJdHJhdihkaWZmLHRvQ2hhbmdlKSAKCQkJdG9nZ2xlKGRpZmYuZi5mLGRpZmYuZi5zLGRpZmYucy5mLCBkaWZmLnMucyk7Cgl9Cn0KCi8qVCBzaWduZWRQb2x5Vm9sdW1lKGNvbnN0IHZQMyYgcCwgY29uc3QgdmVjdG9yPEY+JiB0cmlsaXN0KSB7CglUIHYgPSAwOwoJdHJhdihpLHRyaWxpc3QpIHYgKz0gZG90KGNyb3NzKHBbaS5hXSxwW2kuYl0pLHBbaS5jXSk7CglyZXR1cm4gdi82Owp9Ki8KCmludCBtYWluKCkgewoJaW9zX2Jhc2U6OnN5bmNfd2l0aF9zdGRpbygwKTsgY2luLnRpZSgwKTsKCWNvdXQgPDwgZml4ZWQgPDwgc2V0cHJlY2lzaW9uKDQpOwoJaW50IE47Cgl3aGlsZSAoY2luID4+IE4pIHsKCQlodWxsLmNsZWFyKCk7CgkJdlAzIHYoTik7IHJlKHYpOwoJCW1ha2VIdWxsKHYpOwoJCXNldDxQMz4gZmFjZXM7CgkJbGQgdm9sID0gMCwgc2EgPSAwOwoJCXRyYXYodCxodWxsKSB7CgkJCWF1dG8gVCA9IHQuZjsKCQkJaWYgKG9uU2FtZUhhbGZTcGFjZSh2W1RbMF1dK2Nyb3NzKHZbVFswXV0sdltUWzFdXSx2W1RbMl1dKSx2W3Quc10sdltUWzBdXSx2W1RbMV1dLHZbVFsyXV0pKQoJCQkJc3dhcChUWzBdLFRbMV0pOwoJCQlmYWNlcy5pbnNlcnQodW5pdChjcm9zcyh2W1RbMF1dLHZbVFsxXV0sdltUWzJdXSkpKTsKCQkJLy8gdm9sICs9IGRvdChjcm9zcyh2W1RbMF1dLHZbVFsxXV0pLHZbVFsyXV0pOwoJCQkvLyBzYSArPSBhYnMoY3Jvc3ModltUWzBdXSx2W1RbMV1dLHZbVFsyXV0pKTsKCQkJLy9wcygiRkFDRSIsdltUWzBdXSx2W1RbMV1dLHZbVFsyXV0pOwoJCQkvLyBwcygiQUgiLHZbVFswXV0sdltUWzFdXSx2W1RbMl1dLHZbdC5zXSk7CgkJCS8vcHMoY3Jvc3ModltUWzBdXSx2W1RbMV1dLHZbVFsyXV0pLHZbdC5zXSk7CgkJfQoJCS8vIHRyYXYodCxmYWNlcykgcHModCk7CgkJcHMoc3ooZmFjZXMpKTsKCX0KCS8qCgl2UDMgdjsKCXYucGIoezAsMCwwfSk7IAoJdi5wYih7MSwwLDB9KTsgCgl2LnBiKHswLDEsMH0pOyAKCXYucGIoezAsMCwxfSk7IAoJLy8gRjBSKGksOCkgdi5wYihQM3tpLzQlMixpLzIlMixpJTJ9KTsKCUYwUihpLDY0KSB2LnBiKFAze2kvMTYlNCxpLzQlNCxpJTR9KTsKCXJhbmRvbV9zaHVmZmxlKGFsbCh2KSk7CgltYWtlSHVsbCh2KTsKCSovCgkvLyB5b3Ugc2hvdWxkIGFjdHVhbGx5IHJlYWQgdGhlIHN0dWZmIGF0IHRoZSBib3R0b20KfQoKLyogc3R1ZmYgeW91IHNob3VsZCBsb29rIGZvcgoJKiBpbnQgb3ZlcmZsb3csIGFycmF5IGJvdW5kcwoJKiBzcGVjaWFsIGNhc2VzIChuPTE/KSwgc2xvdyBtdWx0aXNldCBvcGVyYXRpb25zCgkqIGRvIHNtdGggaW5zdGVhZCBvZiBub3RoaW5nIGFuZCBzdGF5IG9yZ2FuaXplZAoqLw==