

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<stdlib.h>
#include<string.h>
#define re register int
#define fo(i,a,b) for (re i=a;i<=b;i++)
using namespace std;
const int inf=0x3f;
const int maxn=200000+50;
const int mxn=100000+50;
int T,n,m,k,p,sum1,sum2;
int head[mxn],rev[mxn],dist[mxn],vis[mxn],wd[mxn][50+15],f[mxn][50+15];
//设f[u][know]为到u点时与从终点开始的最短路的偏移量为know的时候的总方案数目。
bool flag;
struct EDGE
{
int to,next,val;
}edge[maxn],reve[maxn];
inline int read() {
char ch = getchar();int ret=0;
while(ch<'0'||ch >'9') ch=getchar();
while(ch<='9'&&ch>='0') ret=ret*10+ch-'0',ch=getchar();
return ret;
}
void init()
{
memset(head,-1,sizeof(head));
memset(rev,-1,sizeof(rev));
sum1=0;sum2=0;
memset(edge,0,sizeof(edge));
memset(reve,0,sizeof(reve));
memset(f,-1,sizeof(f));
flag=false;
}
void add(int x,int y,int z)
{
edge[++sum1]=(EDGE){y,head[x],z};
head[x]=sum1;
}
void addr(int x,int y,int z)
{
reve[++sum2]=(EDGE){y,rev[x],z};
rev[x]=sum2;
}
void spfa()
{
queue <int> q;
memset(dist,inf,sizeof(dist));
memset(vis,0,sizeof(vis));
dist[n]=0;
vis[n]=1;
q.push(n);
while (!q.empty())
{
int x=q.front();q.pop();vis[x]=0;
for (int i=rev[x];i!=-1;i=reve[i].next)
if (dist[reve[i].to]>dist[x]+reve[i].val){
dist[reve[i].to]=dist[x]+reve[i].val;
if (!vis[reve[i].to])
{
vis[reve[i].to]=1;
q.push(reve[i].to);
}
}
}
}
int dfs(int u,int know)
{
if (wd[u][know]) {flag=true;return 0;}
if (f[u][know]>0) return f[u][know];
wd[u][know]=1;
int sum=0;
for (int i=head[u];i!=-1;i=edge[i].next)
{
int tmp=know-(dist[edge[i].to]+edge[i].val-dist[u]);
if (tmp<0||tmp>k) continue;
sum=(sum+dfs(edge[i].to,tmp))%p;
if (flag) return 0;
}
if (u==n&&know==0) sum=1;
wd[u][know]=0;
return f[u][know]=sum;
}
int main()
{
T=read();
while (T--)
{
init();
scanf("%d%d%d%d",&n,&m,&k,&p);
fo(i,1,m)
{
int x=read(),y=read(),z=read();
add(x,y,z);
addr(y,x,z);
}
spfa();
int ans=0;
fo(i,0,k)
{
memset(wd,0,sizeof(wd));
ans=(ans+dfs(1,i))%p;
}
if (flag) puts("-1");else printf("%d\n",ans);
}
return 0;
}