#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#define inf 0x3f3f3f3f
using namespace std;
int n,m,k,p,T;
int index1[100005],index2[100005];
struct unit{int to,next,w;}edge1[200005],edge2[200005];
int dis1[100005],dis2[100005],valid[100005],D,vist[100005];
int f[100005][55],vis[100005][55];
struct unit2
{
    int x,d;
    bool operator < (const unit2 &x) const
    {
        return x.d<d;
    }
};
void init()
{
    memset(index1,0,sizeof(index1));
    memset(index2,0,sizeof(index2));
    memset(dis1,0x3f,sizeof(dis1));
    memset(dis2,0x3f,sizeof(dis2));
    memset(valid,0,sizeof(valid));
    memset(f,0,sizeof(f));
    memset(vis,0,sizeof(vis));
    for(int i=0;i<=k;i++)
        f[n][i]=1;/*
    printf("%d: ",n);
    for(int i=0;i<=k;i++)
        printf("%d ",f[n][i]);
    printf("\n");*/
}
void dijkstra()
{
    priority_queue<unit2>q1;
    dis1[1]=0;
    q1.push({1,0});
    int surplus=1,head;
    memset(vist,0,sizeof(vist));
    while(surplus)
    {
        head=q1.top().x;
        q1.pop();
        if(vist[head]) continue;
        vist[head]=1;
        surplus--;
        for(int i=index1[head],update,son;i;i=edge1[i].next)
        {
            update=dis1[head]+edge1[i].w;
            son=edge1[i].to;
            if(update<dis1[son])
            {
                surplus+=(dis1[son]==inf);
                dis1[son]=update;
                q1.push({son,update});
            }
        }
    }
    D=dis1[n]+k;
    priority_queue<unit2>q2;
    dis2[n]=0;
    q2.push({n,0});
    surplus=1;
    memset(vist,0,sizeof(vist));
    while(surplus)
    {
        head=q2.top().x;
        q2.pop();
        if(vist[head]) continue;
        surplus--;
        vist[head]=1;
        valid[head]=((dis1[head]+dis2[head])<=D);
        for(int i=index2[head],update,son;i;i=edge2[i].next)
        {
            update=dis2[head]+edge2[i].w;
            son=edge2[i].to;
            if(update<dis2[son])
            {
                surplus+=(dis2[son]==inf);
                dis2[son]=update;
                q2.push({son,dis2[son]});
            }
        }
    }
}
int dfs(int x,int extra)
{
    if(vis[x][extra]<0) return -1;
    if(!vis[x][extra])
    {
        vis[x][extra]=-1;
        for(int i=index1[x],son,ex,temp;i;i=edge1[i].next)
        {
            son=edge1[i].to;
            if(valid[son])
            {
                ex=dis1[x]+extra+edge1[i].w-dis1[son];
                if(ex<=k&&ex+dis1[son]+dis2[son]<=D)
                {
                    temp=dfs(son,ex);
                    if(temp<0) return -1;
                    f[x][extra]=(f[x][extra]+temp)%p;
                }
            }
        }
        vis[x][extra]=1;
    }
    //printf("%d %d %d\n",x,extra,f[x][extra]);
    return f[x][extra];
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d",&n,&m,&k,&p);
        init();
        for(int i=1,a,b,c;i<=m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            edge1[i]={b,index1[a],c};
            index1[a]=i;
            edge2[i]={a,index2[b],c};
            index2[b]=i;
        }
        dijkstra();
        printf("%d\n",dfs(1,0));
    }
    return 0;
}