#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cassert>
#include<iostream>
#define Rep(i,a,b) for(register int i=(a);i<=(b);++i)
#define Repe(i,a,b) for(register int i=(a);i>=(b);--i)
#define rep(i,a,b) for(register int i=(a);i<(b);++i)
#define pb push_back
#define mx(a,b) (a>b?a:b)
#define mn(a,b) (a<b?a:b)
typedef unsigned long long uint64;
typedef unsigned int uint32;
typedef long long ll;
using namespace std;
namespace IO
{
const uint32 Buffsize=1<<15,Output=1<<24;
static char Ch[Buffsize],*S=Ch,*T=Ch;
inline char getc()
{
return((S==T)&&(T=(S=Ch)+fread(Ch,1,Buffsize,stdin),S==T)?0:*S++);
}
static char Out[Output],*nowps=Out;
inline void flush(){fwrite(Out,1,nowps-Out,stdout);nowps=Out;}
template<typename T>inline void read(T&x)
{
x=0;static char ch;T f=1;
for(ch=getc();!isdigit(ch);ch=getc())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getc())x=x*10+(ch^48);
x*=f;
}
template<typename T>inline void write(T x,char ch='\n')
{
if(!x)*nowps++='0';
if(x<0)*nowps++='-',x=-x;
static uint32 sta[111],tp;
for(tp=0;x;x/=10)sta[++tp]=x%10;
for(;tp;*nowps++=sta[tp--]^48);
*nowps++=ch;
}
}
using namespace IO;
void file()
{
#ifndef ONLINE_JUDGE
FILE*DSD=freopen("water.in","r",stdin);
FILE*CSC=freopen("water.out","w",stdout);
#endif
}
const int MAXN=1<<17;
static int mod;
namespace poly
{
inline int power(int u,int v)
{
register int sm=1;
for(;v;v>>=1,u=(uint64)u*u%mod)if(v&1)
sm=(uint64)sm*u%mod;
return sm;
}
static int Len,rev[MAXN];
static struct comp
{
double re,im;
comp(){}
comp(double _r,double _i):re(_r),im(_i){}
comp operator+(const comp&a){return comp(re+a.re,im+a.im);}
comp operator-(const comp&a){return comp(re-a.re,im-a.im);}
comp operator*(const comp&a)
{return comp(re*a.re-im*a.im,re*a.im+im*a.re);}
comp operator/(const int&a){return comp(re/a,im/a);}
}g[19][MAXN];
namespace MTT
{
const double pi=acos(-1);
inline void predone()
{
Rep(i,1,17)rep(j,0,1<<i)
g[i][j]=comp(cos(2*pi*j/pow(2,i)),sin(2*pi*j/pow(2,i)));
}
inline void FFT(comp*F,int tl)
{
rep(i,0,Len)if(i<rev[i])swap(F[rev[i]],F[i]);
for(register int i=2,ii=1,t=1;i<=Len;i<<=1,ii<<=1,++t)
for(register int j=0;j<Len;j+=i)rep(k,0,ii)
{
comp x=F[j+k+ii]*g[t][k];
F[j+k+ii]=F[j+k]-x;
F[j+k]=F[j+k]+x;
}
if(tl==-1)
{
reverse(F+1,F+Len);
rep(i,0,Len)F[i]=F[i]/Len;
}
}
static comp Z[MAXN];
inline void DBLFFT(comp*F,comp*G,int tl)
{
if(tl==1)
{
memcpy(Z,F,sizeof(comp)*Len);
FFT(Z,1);
memcpy(F,Z,sizeof(comp)*Len);
reverse(F+1,F+Len);
rep(i,0,Len)F[i].im=-F[i].im;
rep(i,0,Len)G[i]=(Z[i]-F[i])/2,F[i]=(Z[i]+F[i])/2
,swap(G[i].re,G[i].im),G[i].im=-G[i].im;
}
else
{
rep(i,0,Len)F[i]=comp(F[i].re-G[i].im,F[i].im+G[i].re);
FFT(F,-1);
rep(i,0,Len)G[i]=comp(F[i].im,0),F[i]=comp(F[i].re,0);
}
}
}
using MTT::predone;
using MTT::DBLFFT;
using MTT::FFT;
inline void calrev()
{
int II=log(Len)/log(2)-1;
Rep(i,1,Len-1)rev[i]=rev[i>>1]>>1|(i&1)<<II;
}
inline int ad(int u,int v)
{return ((unsigned)u+v>=mod?(unsigned)u+v-mod:u+v);}
static int X[MAXN],Y[MAXN],Iv[MAXN],mlx[MAXN];
static comp A[MAXN],B[MAXN],C[MAXN],D[MAXN];
inline void mul(int*F,int*G,int*H,int lenl,int lenr)
{
if((ll)lenl*lenr<=300)
{
Rep(i,0,lenl+lenr)mlx[i]=0;
Rep(i,0,lenl)Rep(j,0,lenr)
mlx[i+j]=(mlx[i+j]+(ll)F[i]*G[j])%mod;
Rep(i,0,lenl+lenr)H[i]=mlx[i];
return;
}
for(Len=2;Len<=lenl+lenr;Len<<=1);
calrev();
rep(i,0,Len)A[i]=i<=lenl?comp(F[i]>>15,F[i]&32767):comp(0,0),
C[i]=i<=lenr?comp(G[i]>>15,G[i]&32767):comp(0,0);
DBLFFT(A,B,1),DBLFFT(C,D,1);
rep(i,0,Len)
{
register comp t=A[i];
A[i]=B[i]*C[i]+A[i]*D[i];
B[i]=B[i]*D[i];
C[i]=C[i]*t;
}
DBLFFT(A,B,-1),FFT(C,-1);
rep(i,0,Len)
{
register int lz=((((ll)floor(C[i].re+0.5))%mod<<30)%mod
+((ll)floor(A[i].re+0.5))%mod*32768+(ll)floor(B[i].re+0.5))%mod;
H[i]=i<=lenl+lenr?lz:0;
}
}
inline void Inv(int*F,int*G,int ln)
{
Iv[0]=power(F[0],mod-2);
for(register int Ln=2;Ln>>1<=ln;Ln<<=1)
{
rep(i,ln+1,Ln)F[i]=0;
rep(i,0,Ln)X[i]=F[i],Y[i]=0;
rep(i,0,(Ln>>1))Y[i]=Iv[i];
mul(Y,X,X,(Ln>>1)-1,Ln-1),--X[0];
mul(X,Y,X,Ln-1,(Ln>>1)-1);
rep(i,(Ln>>1),Ln)Iv[i]=mod-X[i];
}
Rep(i,0,ln)G[i]=Iv[i];
}
static int ExX[MAXN],ExY[MAXN];
inline void Div(int*F,int*G,int*Q,int*R,int lenf,int leng)
{
Rep(i,0,lenf)ExX[i]=F[lenf-i];
Rep(i,0,leng)ExY[i]=G[leng-i];
Rep(i,leng+1,lenf-leng)ExY[i]=0;
Inv(ExY,ExY,lenf-leng);
Rep(i,lenf-leng+1,lenf)ExX[i]=0;
Rep(i,lenf-leng+1,leng)ExY[i]=0;
mul(ExX,ExY,ExY,lenf-leng,lenf-leng);
Rep(i,lenf-leng+1,(lenf-leng)<<1)ExY[i]=0;
Rep(i,0,(lenf-leng)>>1)swap(ExY[i],ExY[lenf-leng-i]);
mul(ExY,G,ExX,lenf-leng,leng);
Rep(i,0,leng-1)R[i]=ad(F[i],mod-ExX[i]);
Rep(i,0,lenf-leng)Q[i]=ExY[i];
}
namespace Extend
{
static int solv[18][2][MAXN];
void calc(int*a,int l,int r,int lev,int dir)
{
if(l==r)
{
solv[lev][dir][0]=mod-a[l];
solv[lev][dir][1]=1;return;
}
int md=(l+r)>>1;
calc(a,l,md,lev+1,0),calc(a,md+1,r,lev+1,1);
mul(solv[lev+1][0],solv[lev+1][1],solv[lev][dir],md-l+1,r-md);
}
static int pol[18][MAXN],Q[MAXN];
void getnum(int*a,int*ans,int l,int r,int lev,int n)
{
if(n>r-l)
{
calc(a,l,r,0,0);
Div(pol[lev-(lev>0)],solv[0][0],Q,pol[lev],n,r-l+1);
n=r-l;
}
else if(lev){Rep(i,0,n)pol[lev][i]=pol[lev-1][i];}
if(l==r)
{
ans[l]=pol[lev][0];
return;
}
int md=(l+r)>>1;
getnum(a,ans,l,md,lev+1,n);
getnum(a,ans,md+1,r,lev+1,n);
}
}
}
using poly::power;
using poly::predone;
using poly::ad;
using poly::Extend::pol;
using poly::Extend::getnum;
using poly::Extend::calc;
using poly::Extend::solv;
static int n,Z[MAXN],as[MAXN];
void solve()
{
read(n),read(mod);
int v=sqrt(n);
Rep(i,1,v)Z[i]=mod-i;
calc(Z,1,v,0,0);
memcpy(pol[0],solv[0][0],sizeof(int)*(v+1));
Rep(i,1,v)Z[i]=(i-1)*v;
getnum(Z,as,1,v,0,v);
static int ans=1;
Rep(i,1,v)ans=(ll)ans*as[i]%mod;
Rep(i,v*v+1,n)ans=(ll)ans*i%mod;
cout<<ans<<endl;
}
int main()
{
int T;read(T);
while(T--)solve();
}
I2luY2x1ZGU8Y3N0ZGlvPgojaW5jbHVkZTxjc3RkbGliPgojaW5jbHVkZTxjY3R5cGU+CiNpbmNsdWRlPGNzdHJpbmc+CiNpbmNsdWRlPGFsZ29yaXRobT4KI2luY2x1ZGU8Y21hdGg+CiNpbmNsdWRlPGNhc3NlcnQ+CiNpbmNsdWRlPGlvc3RyZWFtPgojZGVmaW5lIFJlcChpLGEsYikgZm9yKHJlZ2lzdGVyIGludCBpPShhKTtpPD0oYik7KytpKQojZGVmaW5lIFJlcGUoaSxhLGIpIGZvcihyZWdpc3RlciBpbnQgaT0oYSk7aT49KGIpOy0taSkKI2RlZmluZSByZXAoaSxhLGIpIGZvcihyZWdpc3RlciBpbnQgaT0oYSk7aTwoYik7KytpKQojZGVmaW5lIHBiIHB1c2hfYmFjawojZGVmaW5lIG14KGEsYikgKGE+Yj9hOmIpCiNkZWZpbmUgbW4oYSxiKSAoYTxiP2E6YikKdHlwZWRlZiB1bnNpZ25lZCBsb25nIGxvbmcgdWludDY0Owp0eXBlZGVmIHVuc2lnbmVkIGludCB1aW50MzI7CnR5cGVkZWYgbG9uZyBsb25nIGxsOwp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKbmFtZXNwYWNlIElPCnsKCWNvbnN0IHVpbnQzMiBCdWZmc2l6ZT0xPDwxNSxPdXRwdXQ9MTw8MjQ7CglzdGF0aWMgY2hhciBDaFtCdWZmc2l6ZV0sKlM9Q2gsKlQ9Q2g7CglpbmxpbmUgY2hhciBnZXRjKCkKCXsKCQlyZXR1cm4oKFM9PVQpJiYoVD0oUz1DaCkrZnJlYWQoQ2gsMSxCdWZmc2l6ZSxzdGRpbiksUz09VCk/MDoqUysrKTsKCX0KCXN0YXRpYyBjaGFyIE91dFtPdXRwdXRdLCpub3dwcz1PdXQ7CgkKCWlubGluZSB2b2lkIGZsdXNoKCl7ZndyaXRlKE91dCwxLG5vd3BzLU91dCxzdGRvdXQpO25vd3BzPU91dDt9CgoJdGVtcGxhdGU8dHlwZW5hbWUgVD5pbmxpbmUgdm9pZCByZWFkKFQmeCkKCXsKCQl4PTA7c3RhdGljIGNoYXIgY2g7VCBmPTE7CgkJZm9yKGNoPWdldGMoKTshaXNkaWdpdChjaCk7Y2g9Z2V0YygpKWlmKGNoPT0nLScpZj0tMTsKCQlmb3IoO2lzZGlnaXQoY2gpO2NoPWdldGMoKSl4PXgqMTArKGNoXjQ4KTsKCQl4Kj1mOwoJfQoKCXRlbXBsYXRlPHR5cGVuYW1lIFQ+aW5saW5lIHZvaWQgd3JpdGUoVCB4LGNoYXIgY2g9J1xuJykKCXsKCQlpZigheCkqbm93cHMrKz0nMCc7CgkJaWYoeDwwKSpub3dwcysrPSctJyx4PS14OwoJCXN0YXRpYyB1aW50MzIgc3RhWzExMV0sdHA7CgkJZm9yKHRwPTA7eDt4Lz0xMClzdGFbKyt0cF09eCUxMDsKCQlmb3IoO3RwOypub3dwcysrPXN0YVt0cC0tXV40OCk7CgkJKm5vd3BzKys9Y2g7Cgl9Cn0KdXNpbmcgbmFtZXNwYWNlIElPOwoKdm9pZCBmaWxlKCkKewojaWZuZGVmIE9OTElORV9KVURHRQoJRklMRSpEU0Q9ZnJlb3Blbigid2F0ZXIuaW4iLCJyIixzdGRpbik7CglGSUxFKkNTQz1mcmVvcGVuKCJ3YXRlci5vdXQiLCJ3IixzdGRvdXQpOwojZW5kaWYKfQoKY29uc3QgaW50IE1BWE49MTw8MTc7CgpzdGF0aWMgaW50IG1vZDsKCm5hbWVzcGFjZSBwb2x5CnsKCWlubGluZSBpbnQgcG93ZXIoaW50IHUsaW50IHYpCgl7CgkJcmVnaXN0ZXIgaW50IHNtPTE7CgkJZm9yKDt2O3Y+Pj0xLHU9KHVpbnQ2NCl1KnUlbW9kKWlmKHYmMSkKCQkJc209KHVpbnQ2NClzbSp1JW1vZDsKCQlyZXR1cm4gc207Cgl9CgoJc3RhdGljIGludCBMZW4scmV2W01BWE5dOwoKCXN0YXRpYyBzdHJ1Y3QgY29tcAoJewoJCWRvdWJsZSByZSxpbTsKCgkJY29tcCgpe30KCgkJY29tcChkb3VibGUgX3IsZG91YmxlIF9pKTpyZShfciksaW0oX2kpe30KCgkJY29tcCBvcGVyYXRvcisoY29uc3QgY29tcCZhKXtyZXR1cm4gY29tcChyZSthLnJlLGltK2EuaW0pO30KCgkJY29tcCBvcGVyYXRvci0oY29uc3QgY29tcCZhKXtyZXR1cm4gY29tcChyZS1hLnJlLGltLWEuaW0pO30KCgkJY29tcCBvcGVyYXRvciooY29uc3QgY29tcCZhKQoJCXtyZXR1cm4gY29tcChyZSphLnJlLWltKmEuaW0scmUqYS5pbStpbSphLnJlKTt9CgoJCWNvbXAgb3BlcmF0b3IvKGNvbnN0IGludCZhKXtyZXR1cm4gY29tcChyZS9hLGltL2EpO30KCX1nWzE5XVtNQVhOXTsKCgluYW1lc3BhY2UgTVRUCgl7CgkJY29uc3QgZG91YmxlIHBpPWFjb3MoLTEpOwoKCQlpbmxpbmUgdm9pZCBwcmVkb25lKCkKCQl7CgkJCVJlcChpLDEsMTcpcmVwKGosMCwxPDxpKQoJCQkJZ1tpXVtqXT1jb21wKGNvcygyKnBpKmovcG93KDIsaSkpLHNpbigyKnBpKmovcG93KDIsaSkpKTsKCQl9CgoJCWlubGluZSB2b2lkIEZGVChjb21wKkYsaW50IHRsKQoJCXsKCQkJcmVwKGksMCxMZW4paWYoaTxyZXZbaV0pc3dhcChGW3JldltpXV0sRltpXSk7CgkJCWZvcihyZWdpc3RlciBpbnQgaT0yLGlpPTEsdD0xO2k8PUxlbjtpPDw9MSxpaTw8PTEsKyt0KQoJCQkJZm9yKHJlZ2lzdGVyIGludCBqPTA7ajxMZW47ais9aSlyZXAoaywwLGlpKQoJCQkJewoJCQkJCWNvbXAgeD1GW2oraytpaV0qZ1t0XVtrXTsKCQkJCQlGW2oraytpaV09RltqK2tdLXg7CgkJCQkJRltqK2tdPUZbaitrXSt4OwoJCQkJfQoJCQlpZih0bD09LTEpCgkJCXsKCQkJCXJldmVyc2UoRisxLEYrTGVuKTsKCQkJCXJlcChpLDAsTGVuKUZbaV09RltpXS9MZW47CgkJCX0KCQl9CgoJCXN0YXRpYyBjb21wIFpbTUFYTl07CgoJCWlubGluZSB2b2lkIERCTEZGVChjb21wKkYsY29tcCpHLGludCB0bCkKCQl7CgkJCWlmKHRsPT0xKQoJCQl7CgkJCQltZW1jcHkoWixGLHNpemVvZihjb21wKSpMZW4pOwoJCQkJRkZUKFosMSk7CgkJCQltZW1jcHkoRixaLHNpemVvZihjb21wKSpMZW4pOwoJCQkJcmV2ZXJzZShGKzEsRitMZW4pOwoJCQkJcmVwKGksMCxMZW4pRltpXS5pbT0tRltpXS5pbTsKCQkJCXJlcChpLDAsTGVuKUdbaV09KFpbaV0tRltpXSkvMixGW2ldPShaW2ldK0ZbaV0pLzIKCQkJCQksc3dhcChHW2ldLnJlLEdbaV0uaW0pLEdbaV0uaW09LUdbaV0uaW07CgkJCX0KCQkJZWxzZQoJCQl7CgkJCQlyZXAoaSwwLExlbilGW2ldPWNvbXAoRltpXS5yZS1HW2ldLmltLEZbaV0uaW0rR1tpXS5yZSk7CgkJCQlGRlQoRiwtMSk7CgkJCQlyZXAoaSwwLExlbilHW2ldPWNvbXAoRltpXS5pbSwwKSxGW2ldPWNvbXAoRltpXS5yZSwwKTsKCQkJfQoJCX0KCX0KCXVzaW5nIE1UVDo6cHJlZG9uZTsKCXVzaW5nIE1UVDo6REJMRkZUOwoJdXNpbmcgTVRUOjpGRlQ7CgoJaW5saW5lIHZvaWQgY2FscmV2KCkKCXsKCQlpbnQgSUk9bG9nKExlbikvbG9nKDIpLTE7CgkJUmVwKGksMSxMZW4tMSlyZXZbaV09cmV2W2k+PjFdPj4xfChpJjEpPDxJSTsKCX0KCglpbmxpbmUgaW50IGFkKGludCB1LGludCB2KQoJe3JldHVybiAoKHVuc2lnbmVkKXUrdj49bW9kPyh1bnNpZ25lZCl1K3YtbW9kOnUrdik7fQoKCXN0YXRpYyBpbnQgWFtNQVhOXSxZW01BWE5dLEl2W01BWE5dLG1seFtNQVhOXTsKCglzdGF0aWMgY29tcCBBW01BWE5dLEJbTUFYTl0sQ1tNQVhOXSxEW01BWE5dOwoKCWlubGluZSB2b2lkIG11bChpbnQqRixpbnQqRyxpbnQqSCxpbnQgbGVubCxpbnQgbGVucikKCXsKCQlpZigobGwpbGVubCpsZW5yPD0zMDApCgkJewoJCQlSZXAoaSwwLGxlbmwrbGVuciltbHhbaV09MDsKCQkJUmVwKGksMCxsZW5sKVJlcChqLDAsbGVucikKCQkJCW1seFtpK2pdPShtbHhbaStqXSsobGwpRltpXSpHW2pdKSVtb2Q7CgkJCVJlcChpLDAsbGVubCtsZW5yKUhbaV09bWx4W2ldOwoJCQlyZXR1cm47CgkJfQoJCWZvcihMZW49MjtMZW48PWxlbmwrbGVucjtMZW48PD0xKTsKCQljYWxyZXYoKTsKCQlyZXAoaSwwLExlbilBW2ldPWk8PWxlbmw/Y29tcChGW2ldPj4xNSxGW2ldJjMyNzY3KTpjb21wKDAsMCksCgkJCUNbaV09aTw9bGVucj9jb21wKEdbaV0+PjE1LEdbaV0mMzI3NjcpOmNvbXAoMCwwKTsKCQlEQkxGRlQoQSxCLDEpLERCTEZGVChDLEQsMSk7CgkJcmVwKGksMCxMZW4pCgkJewoJCQlyZWdpc3RlciBjb21wIHQ9QVtpXTsKCQkJQVtpXT1CW2ldKkNbaV0rQVtpXSpEW2ldOwoJCQlCW2ldPUJbaV0qRFtpXTsKCQkJQ1tpXT1DW2ldKnQ7CgkJfQoJCURCTEZGVChBLEIsLTEpLEZGVChDLC0xKTsKCQlyZXAoaSwwLExlbikKCQl7CgkJCXJlZ2lzdGVyIGludCBsej0oKCgobGwpZmxvb3IoQ1tpXS5yZSswLjUpKSVtb2Q8PDMwKSVtb2QKCQkJCSArKChsbClmbG9vcihBW2ldLnJlKzAuNSkpJW1vZCozMjc2OCsobGwpZmxvb3IoQltpXS5yZSswLjUpKSVtb2Q7CgkJCUhbaV09aTw9bGVubCtsZW5yP2x6OjA7CgkJfQoJfQoKCWlubGluZSB2b2lkIEludihpbnQqRixpbnQqRyxpbnQgbG4pCgl7CgkJSXZbMF09cG93ZXIoRlswXSxtb2QtMik7CgkJZm9yKHJlZ2lzdGVyIGludCBMbj0yO0xuPj4xPD1sbjtMbjw8PTEpCgkJewoJCQlyZXAoaSxsbisxLExuKUZbaV09MDsKCQkJcmVwKGksMCxMbilYW2ldPUZbaV0sWVtpXT0wOwoJCQlyZXAoaSwwLChMbj4+MSkpWVtpXT1JdltpXTsKCQkJbXVsKFksWCxYLChMbj4+MSktMSxMbi0xKSwtLVhbMF07CgkJCW11bChYLFksWCxMbi0xLChMbj4+MSktMSk7CgkJCXJlcChpLChMbj4+MSksTG4pSXZbaV09bW9kLVhbaV07CgkJfQoJCVJlcChpLDAsbG4pR1tpXT1JdltpXTsKCX0KCglzdGF0aWMgaW50IEV4WFtNQVhOXSxFeFlbTUFYTl07CgoJaW5saW5lIHZvaWQgRGl2KGludCpGLGludCpHLGludCpRLGludCpSLGludCBsZW5mLGludCBsZW5nKQoJewoJCVJlcChpLDAsbGVuZilFeFhbaV09RltsZW5mLWldOwoJCVJlcChpLDAsbGVuZylFeFlbaV09R1tsZW5nLWldOwoJCVJlcChpLGxlbmcrMSxsZW5mLWxlbmcpRXhZW2ldPTA7CgkJSW52KEV4WSxFeFksbGVuZi1sZW5nKTsKCQlSZXAoaSxsZW5mLWxlbmcrMSxsZW5mKUV4WFtpXT0wOwoJCVJlcChpLGxlbmYtbGVuZysxLGxlbmcpRXhZW2ldPTA7CgkJbXVsKEV4WCxFeFksRXhZLGxlbmYtbGVuZyxsZW5mLWxlbmcpOwoJCVJlcChpLGxlbmYtbGVuZysxLChsZW5mLWxlbmcpPDwxKUV4WVtpXT0wOwoJCVJlcChpLDAsKGxlbmYtbGVuZyk+PjEpc3dhcChFeFlbaV0sRXhZW2xlbmYtbGVuZy1pXSk7CgkJbXVsKEV4WSxHLEV4WCxsZW5mLWxlbmcsbGVuZyk7CgkJUmVwKGksMCxsZW5nLTEpUltpXT1hZChGW2ldLG1vZC1FeFhbaV0pOwoJCVJlcChpLDAsbGVuZi1sZW5nKVFbaV09RXhZW2ldOwoJfQoKCW5hbWVzcGFjZSBFeHRlbmQKCXsKCQlzdGF0aWMgaW50IHNvbHZbMThdWzJdW01BWE5dOwoKCQl2b2lkIGNhbGMoaW50KmEsaW50IGwsaW50IHIsaW50IGxldixpbnQgZGlyKQoJCXsKCQkJaWYobD09cikKCQkJewoJCQkJc29sdltsZXZdW2Rpcl1bMF09bW9kLWFbbF07CgkJCQlzb2x2W2xldl1bZGlyXVsxXT0xO3JldHVybjsKCQkJfQoJCQlpbnQgbWQ9KGwrcik+PjE7CgkJCWNhbGMoYSxsLG1kLGxldisxLDApLGNhbGMoYSxtZCsxLHIsbGV2KzEsMSk7CgkJCW11bChzb2x2W2xldisxXVswXSxzb2x2W2xldisxXVsxXSxzb2x2W2xldl1bZGlyXSxtZC1sKzEsci1tZCk7CgkJfQoKCQlzdGF0aWMgaW50IHBvbFsxOF1bTUFYTl0sUVtNQVhOXTsKCQkKCQl2b2lkIGdldG51bShpbnQqYSxpbnQqYW5zLGludCBsLGludCByLGludCBsZXYsaW50IG4pCgkJewoJCQlpZihuPnItbCkKCQkJewoJCQkJY2FsYyhhLGwsciwwLDApOwoJCQkJRGl2KHBvbFtsZXYtKGxldj4wKV0sc29sdlswXVswXSxRLHBvbFtsZXZdLG4sci1sKzEpOwoJCQkJbj1yLWw7CgkJCX0KCQkJZWxzZSBpZihsZXYpe1JlcChpLDAsbilwb2xbbGV2XVtpXT1wb2xbbGV2LTFdW2ldO30KCQkJaWYobD09cikKCQkJewoJCQkJYW5zW2xdPXBvbFtsZXZdWzBdOwoJCQkJcmV0dXJuOwoJCQl9CgkJCWludCBtZD0obCtyKT4+MTsKCQkJZ2V0bnVtKGEsYW5zLGwsbWQsbGV2KzEsbik7CgkJCWdldG51bShhLGFucyxtZCsxLHIsbGV2KzEsbik7CgkJfQoJfQp9CnVzaW5nIHBvbHk6OnBvd2VyOwp1c2luZyBwb2x5OjpwcmVkb25lOwp1c2luZyBwb2x5OjphZDsKdXNpbmcgcG9seTo6RXh0ZW5kOjpwb2w7CnVzaW5nIHBvbHk6OkV4dGVuZDo6Z2V0bnVtOwp1c2luZyBwb2x5OjpFeHRlbmQ6OmNhbGM7CnVzaW5nIHBvbHk6OkV4dGVuZDo6c29sdjsKCnN0YXRpYyBpbnQgbixaW01BWE5dLGFzW01BWE5dOwoKdm9pZCBzb2x2ZSgpCnsKCXJlYWQobikscmVhZChtb2QpOwoJaW50IHY9c3FydChuKTsKCVJlcChpLDEsdilaW2ldPW1vZC1pOwoJY2FsYyhaLDEsdiwwLDApOwoJbWVtY3B5KHBvbFswXSxzb2x2WzBdWzBdLHNpemVvZihpbnQpKih2KzEpKTsKCVJlcChpLDEsdilaW2ldPShpLTEpKnY7CglnZXRudW0oWixhcywxLHYsMCx2KTsKCXN0YXRpYyBpbnQgYW5zPTE7CglSZXAoaSwxLHYpYW5zPShsbClhbnMqYXNbaV0lbW9kOwoJUmVwKGksdip2KzEsbilhbnM9KGxsKWFucyppJW1vZDsKCWNvdXQ8PGFuczw8ZW5kbDsKfQppbnQgbWFpbigpCnsKICAgIGludCBUO3JlYWQoVCk7CiAgICB3aGlsZShULS0pc29sdmUoKTsKfQ==