#include<iostream>
#include<stdio.h>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<set>
#include<assert.h>
using namespace std;
struct segment_tree
{
	int l,r,cnt,max_id;
};
vector<segment_tree>vec[510010];
vector<int>ll[510010],rr[510010];
int num_node[510010];
segment_tree nw;
struct query
{
	int l,r,pl,pr;
};
query qy[510000];
bool cmp(int id1,int id2)
{
	return qy[id1].pl<qy[id2].pl;
}
struct pp
{
	int id,x;
	bool operator <(const pp &temp)const
	{
		if(x==temp.x)
		{
			if(qy[id].pr-qy[id].pl==qy[temp.id].pr-qy[temp.id].pl)
		       return id<temp.id;
		    return qy[id].pr-qy[id].pl>qy[temp.id].pr-qy[temp.id].pl;
		}
		return x<temp.x;
	}
};
set<pp>hs;
set<pp>::iterator it;
pp now;
struct xx
{
	int x,flag,id;
	bool operator <(const xx &temp)const
	{
		if(x==temp.x)
		{
		   if(flag==temp.flag)
		   {
		   	   if(qy[id].pr-qy[id].pl==qy[temp.id].pr-qy[temp.id].pl)
		          return id<temp.id;
		       return qy[id].pr-qy[id].pl>qy[temp.id].pr-qy[temp.id].pl;
		   }
		   return flag<temp.flag;
		}
		return x<temp.x;
	}
};
xx x[1100000];
int num_q,cnt;
const int maxn=600000;
char str[555555],tr[55555];
int m,len,n,lg[600000],pa[5010000];
int sa[maxn],rnk[maxn],lcp[maxn],fk[20][maxn];
int num[maxn],sum[55555],pos[600000],nxt[600000],ix[510000],ans[2][510000],pre[600000],sz[510000];
vector<int>adj[510000];
inline bool leq(int a1, int a2, int b1, int b2)
{
    return (a1 < b1 || a1 == b1 && a2 <= b2);
}

inline bool leq(int a1, int a2, int a3, int b1, int b2, int b3)
{
    return(a1 < b1 || a1 == b1 && leq(a2, a3, b2, b3));
}

static void radixPass(int* a, int* b, int* r, int n, int K)
{
    int* c = new int[K + 1];
    int i,sum;
    for(i = 0; i <= K; i++)
        c[i] = 0;
    for(i = 0; i < n; i++)
        c[r[a[i]]]++;
    for(i = 0, sum = 0; i <= K; i++)
    {
        int t = c[i];
        c[i] = sum;
        sum += t;
    }
    for(i = 0; i < n; i++)
        b[c[r[a[i]]]++] = a[i];
    delete [] c;
}

void suffixArray(int* T, int* SA, int n, int K)
{
    int n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3, n02 = n0 + n2;
    int* R = new int[n02 + 3]; R[n02] = R[n02+1] = R[n02 + 2] = 0;
    int* SA12 = new int[n02 + 3]; SA12[n02] = SA12[n02 + 1] = SA12[n02 + 2] = 0;
    int* R0 = new int[n0];
    int* SA0 = new int[n0];
    int i,j;
    for(i = 0, j = 0; i < n + (n0 - n1); i++) if(i % 3 != 0) R[j++] = i;
    radixPass(R , SA12, T + 2, n02, K);
    radixPass(SA12, R , T + 1, n02, K);
    radixPass(R , SA12, T , n02, K);
    int name = 0, c0 = -1, c1 = -1, c2 = -1;

    for( i = 0; i < n02; i++)
    {
        if(T[SA12[i]] != c0 || T[SA12[i] + 1] != c1 || T[SA12[i] + 2] != c2)
        {
            name++; c0 = T[SA12[i]]; c1 = T[SA12[i] + 1]; c2 = T[SA12[i] + 2];
        }
        if(SA12[i] % 3 == 1) { R[SA12[i] / 3] = name; }
        else{ R[SA12[i] / 3 + n0] = name; }
    }
    if(name < n02)
    {
        suffixArray(R, SA12, n02, name);
        for(int i = 0; i < n02; i++) R[SA12[i]] = i + 1;
    }
    else
        for(int i = 0; i < n02; i++) SA12[R[i] - 1] = i;
    for(i = 0, j = 0; i < n02; i++) if(SA12[i] < n0) R0[j++] = 3 * SA12[i];
    radixPass(R0, SA0, T, n0, K);
    for(int p = 0, t = n0 - n1, k = 0; k < n; k++)
    {
        #define GetI() (SA12[t] < n0 ? SA12[t] * 3 + 1 : (SA12[t] - n0) * 3 + 2)
        int i = GetI();
        int j = SA0[p];
        if(SA12[t] < n0 ?
        leq(T[i], R[SA12[t] + n0], T[j], R[j / 3]) : leq(T[i],T[i + 1],R[SA12[t] - n0 + 1], T[j],T[j + 1],R[j / 3 + n0]))
        {
            SA[k] = i; t++;
            if(t == n02)
                for(k++; p < n0; p++, k++) SA[k] = SA0[p];
        }
        else{
            SA[k] = j;
            if(++p == n0)for(k++; t < n02; t++, k++) SA[k] = GetI();
        }
    }
    delete [] R; delete [] SA12; delete [] SA0; delete [] R0;
}

void LCP(int *str)
{
    int i,j,k;
    len=n;
    for(k=i=0;i<len;i++)
    {
        if( rnk[i] == len - 1 ) lcp[ rnk[i] ] = k = 0;
        else
        {
            if( k > 0 )    k--;
            j = sa[ rnk[i] + 1];
            for(;str[i+k] == str[j+k];k++);
            lcp[rnk[i]] = k;
        }
    }
}
int rmq(int id1,int id2)
{
	int ip1,ip2,le,ri,id;
	ip1=rnk[id1];
	ip2=rnk[id2];
	if(ip1<ip2)
	{
		le=ip1;
		ri=ip2-1;
	}
	else
	{
		le=ip2;
		ri=ip1-1;
	}
	id=lg[ri-le+1];
	return min(fk[id][le],fk[id][ri+1-(1<<id)]);
}
void insert(int pos,int idx,int id)
{
	int i,j,s,p,q,mid;
	mid=(vec[idx][id].l+vec[idx][id].r)/2;
	if(vec[idx][id].l==vec[idx][id].r)
	{
		vec[idx][id].max_id=vec[idx][id].l;
		vec[idx][id].cnt++;
	    return;
	}
	if(pos<=mid)
	{
		if(ll[idx][id]<0)
		{
			ll[idx][id]=num_node[idx]++;
			ll[idx].push_back(-1);
			rr[idx].push_back(-1);
			nw.l=vec[idx][id].l;
		    nw.r=mid;
		    nw.cnt=0;
		    vec[idx].push_back(nw);
		}
		insert(pos,idx,ll[idx][id]);
	}
	else
	{
		if(rr[idx][id]<0)
		{
		    rr[idx][id]=num_node[idx]++;
		    ll[idx].push_back(-1);
		    rr[idx].push_back(-1);
		    nw.l=mid+1;
		    nw.r=vec[idx][id].r;
		    nw.cnt=0;
		    vec[idx].push_back(nw);
		}
		insert(pos,idx,rr[idx][id]);
	}
	vec[idx][id].cnt=0;
	vec[idx][id].max_id=-1;
	if(ll[idx][id]>=0)
	{
	   vec[idx][id].cnt=vec[idx][ll[idx][id]].cnt;
	   vec[idx][id].max_id=vec[idx][ll[idx][id]].max_id;
	}
	if(rr[idx][id]>=0)
    {
    	if(vec[idx][id].cnt<vec[idx][rr[idx][id]].cnt)
    	{
	    	vec[idx][id].cnt=vec[idx][rr[idx][id]].cnt;
	    	vec[idx][id].max_id=vec[idx][rr[idx][id]].max_id;
	    }
    }
    if(pa[id]==-1)
    {
    	vec[idx].clear();
    	ll[idx].clear();
    	rr[idx].clear();
    }
}
segment_tree query(int left,int right,int idx,int id)
{
	int l=ll[idx][id],r=rr[idx][id];
	segment_tree res,rk;
	res.cnt=0;
	if(left>vec[idx][id].r||right<vec[idx][id].l)
	    return res;
    if(left<=vec[idx][id].l&&right>=vec[idx][id].r)
        return vec[idx][id];
    if(l>=0)
    	res=query(left,right,idx,l);
    if(r>=0)
    {
    	rk=query(left,right,idx,r);
    	if(res.cnt<rk.cnt)
    	  res=rk;
    }
    return res;
}
void solve(int id)
{
	int i,j,s,p,q,ip,ax=0,im,pr;
	im=-1;
	sort(adj[id].begin(),adj[id].end(),cmp);
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i];
		solve(ip);
		if(ax<sz[ix[ip]])
		{
			ax=sz[ix[ip]];
			im=ix[ip];
		}
	}
	if(ax>0)
		ix[id]=im;
	else
	{
	    ix[id]=cnt++;
		nw.l=0;
    	nw.r=m-1;
	    nw.cnt=0;
	    nw.max_id=-1;
	    num_node[ix[id]]=1;
	    ll[ix[id]].push_back(-1);
	    rr[ix[id]].push_back(-1);
	    vec[ix[id]].push_back(nw);
	}
//	if(id==3155)
	  //  printf("im=%d\n",im);
	pr=qy[id].pl;
    sz[ix[id]]=0;
	for(i=0;i<adj[id].size();i++)
    {
    	ip=adj[id][i];
    	for(j=pr;j<qy[ip].pl;j=nxt[j])
    	{
    	//	assert(pos[j]>0);
    	 //   if(i==3155)
    	  //     printf("%d ",pos[j]);
	    	insert(pos[j]-1,ix[id],0);
    	    sz[ix[id]]++;
		}
		if(ix[ip]!=ix[id])
    	{
    		//assert(pos[qy[ip].pl]>0);
	    	for(;j<=qy[ip].pr;j=nxt[j])
	    	   insert(pos[j]-1,ix[id],0);
			sz[ix[id]]+=sz[ix[ip]];
			vec[ix[ip]].clear();
			ll[ix[ip]].clear();
			rr[ix[ip]].clear();
			sz[ix[ip]]=0;
		}
        pr=nxt[qy[ip].pr];
	}
    for(j=pr;j<=qy[id].pr;j=nxt[j])
    {
    	sz[ix[id]]++;
        insert(pos[j]-1,ix[id],0);
    }
  //  if(i==3155)
    //    printf("\n");
	segment_tree nx=query(qy[id].l,qy[id].r,ix[id],0);
    if(nx.cnt==0)
       nx.max_id=qy[id].l;
    ans[0][id]=nx.max_id+1;
    ans[1][id]=nx.cnt;
}
int main()
{
	int i,j,s,p,q,k;
	gets(str);
	n=strlen(str);
	scanf("%d",&m);
	getchar();
	lg[1]=0;
	for(i=2;i<=600000;i++)
		lg[i]=lg[i/2]+1;
	for(i=0;i<n;i++)
	    num[i]=str[i]-'a'+2;
    num[n++]=1;
	for(i=0;i<m;i++)
	{
		gets(tr);
		sum[i]=n;
		len=strlen(tr);
		for(j=0;j<len;j++)
		    num[n++]=tr[j]-'a'+2;
        num[n++]=0;
	}
	sum[i]=n;
	suffixArray(num,sa,n,27);
	for(i=0;i<n;i++)
		rnk[sa[i]]=i;
	for(i=0;i<n;i++)
	   pos[rnk[i]]=0;
    for(i=0;i<m;i++)
    {
    	for(j=sum[i];j<sum[i+1];j++)
    	   pos[rnk[j]]=i+1;
    }
	LCP(num);
	for(i=0;i<n;i++)
	   fk[0][i]=lcp[i];
    for(k=1;(1<<k)<=n;k++)
       for(i=0;i+(1<<k)<=n;i++)
          fk[k][i]=min(fk[k-1][i],fk[k-1][i+(1<<(k-1))]);
    scanf("%d",&num_q);
     nxt[n]=n;
	 for(i=n;i>0;i--)
     {
     	if(i<n&&pos[i]>0)
     	   nxt[i-1]=i;
  	    else
  	       nxt[i-1]=nxt[i];
     }
     pre[0]=-1;
     for(i=0;i<n-1;i++)
     {
     	if(pos[i]>0)
     	   pre[i+1]=i;
  	    else
  	       pre[i+1]=pre[i];
     }
    for(i=0;i<num_q;i++)
    {
    	scanf("%d%d%d%d",&qy[i].l,&qy[i].r,&qy[i].pl,&qy[i].pr);
    	qy[i].l--;
    	qy[i].r--;
    	qy[i].pl--;
    	qy[i].pr--;
    	int l=rnk[qy[i].pl],low,high,mid;
    	low=l+1;
    	high=n-1;
    	int dx=qy[i].pr-qy[i].pl+1;
		while(low<=high)
    	{
	    	mid=(low+high)>>1;
	    	if(rmq(sa[l],sa[mid])>=dx)
	    	   low=mid+1;
  	        else
  	           high=mid-1;
	    }
	    if(pos[high]>0)
	        qy[i].pr=high;
	    else
	        qy[i].pr=pre[high];
		low=0;
	    high=l-1;
	    while(low<=high)
	    {
    		mid=(low+high)>>1;
    		if(rmq(sa[mid],sa[l])>=dx)
    		   high=mid-1;
 		    else
 		       low=mid+1;
    	}
    	if(pos[low]>0)
        	qy[i].pl=low;
        else
            qy[i].pl=nxt[low];
	}
    cnt=0;
    for(i=0;i<num_q;i++)
    {
    	if(qy[i].pl>qy[i].pr)
    	    continue;
    	x[cnt].flag=-1;
    	x[cnt].id=i;
    	x[cnt++].x=qy[i].pl;
    	x[cnt].flag=1;
    	x[cnt].id=i;
    	x[cnt++].x=qy[i].pr;
    }
    sort(x,x+cnt);
    hs.clear();
    for(i=0;i<num_q;i++)
       pa[i]=-1;
    for(i=0;i<cnt;i++)
    {
   	    now.id=x[i].id;
   	    now.x=qy[now.id].pl;
    	if(x[i].flag<0)
	    {
 		    it=hs.upper_bound(now);
    		if(it!=hs.begin())
    		{
    			it--;
		    	pa[now.id]=it->id;
		    }
	    	hs.insert(now);
	    }
	    else
    		hs.erase(now);
    }
    for(i=0;i<=num_q;i++)
       adj[i].clear();
	memset(ix,-1,sizeof(ix));
	for(i=0;i<num_q;i++)
    {
    	if(pa[i]>=0)
    	  adj[pa[i]].push_back(i);
    }
    for(i=0;i<=num_q;i++)
    {
   	   ll[i].clear();
   	   rr[i].clear();
       vec[i].clear();
    }
    cnt=0;
    memset(ans,0,sizeof(ans));
    for(i=0;i<num_q;i++)
        ans[0][i]=qy[i].l+1;
    for(i=0;i<num_q;i++)
    {
    	if(qy[i].pl>qy[i].pr)
    	   continue;
    	if(pa[i]<0)
    	   solve(i);
    }
    for(i=0;i<num_q;i++)
       printf("%d %d\n",ans[0][i],ans[1][i]);
	return 0;
}
/*
suffixtree
3
suffixtreesareawesome
cartesiantreeisworsethansegmenttree
nyeeheeheee
2
1 3 9 9
1 3 10 10

*/


#include<iostream>
#include<stdio.h>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<set>
#include<assert.h>
using namespace std;
struct segment_tree
{
	int l,r,cnt,max_id;
};
vector<segment_tree>vec[510010];
vector<int>ll[510010],rr[510010];
int num_node[510010];
segment_tree nw;
struct query
{
	int l,r,pl,pr;
};
query qy[510000];
bool cmp(int id1,int id2)
{
	return qy[id1].pl<qy[id2].pl;
}
struct pp
{
	int id,x;
	bool operator <(const pp &temp)const
	{
		if(x==temp.x)
		{
			if(qy[id].pr-qy[id].pl==qy[temp.id].pr-qy[temp.id].pl)
		       return id<temp.id;
		    return qy[id].pr-qy[id].pl>qy[temp.id].pr-qy[temp.id].pl;
		}
		return x<temp.x;
	}
};
set<pp>hs;
set<pp>::iterator it;
pp now;
struct xx
{
	int x,flag,id;
	bool operator <(const xx &temp)const
	{
		if(x==temp.x)
		{
		   if(flag==temp.flag)
		   {
		   	   if(qy[id].pr-qy[id].pl==qy[temp.id].pr-qy[temp.id].pl)
		          return id<temp.id;
		       return qy[id].pr-qy[id].pl>qy[temp.id].pr-qy[temp.id].pl;
		   }
		   return flag<temp.flag;
		}
		return x<temp.x;
	}
};
xx x[1100000];
int num_q,cnt;
const int maxn=600000;
char str[555555],tr[55555];
int m,len,n,lg[600000],pa[5010000];
int sa[maxn],rnk[maxn],lcp[maxn],fk[20][maxn];
int num[maxn],sum[55555],pos[600000],nxt[600000],ix[510000],ans[2][510000],pre[600000],sz[510000];
vector<int>adj[510000];
inline bool leq(int a1, int a2, int b1, int b2)
{
    return (a1 < b1 || a1 == b1 && a2 <= b2);
}

inline bool leq(int a1, int a2, int a3, int b1, int b2, int b3)
{
    return(a1 < b1 || a1 == b1 && leq(a2, a3, b2, b3));
}

static void radixPass(int* a, int* b, int* r, int n, int K)
{
    int* c = new int[K + 1];
    int i,sum;
    for(i = 0; i <= K; i++)
        c[i] = 0;
    for(i = 0; i < n; i++)
        c[r[a[i]]]++;
    for(i = 0, sum = 0; i <= K; i++)
    {
        int t = c[i];
        c[i] = sum;
        sum += t;
    }
    for(i = 0; i < n; i++)
        b[c[r[a[i]]]++] = a[i];
    delete [] c;
}

void suffixArray(int* T, int* SA, int n, int K)
{
    int n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3, n02 = n0 + n2;
    int* R = new int[n02 + 3]; R[n02] = R[n02+1] = R[n02 + 2] = 0;
    int* SA12 = new int[n02 + 3]; SA12[n02] = SA12[n02 + 1] = SA12[n02 + 2] = 0;
    int* R0 = new int[n0];
    int* SA0 = new int[n0];
    int i,j;
    for(i = 0, j = 0; i < n + (n0 - n1); i++) if(i % 3 != 0) R[j++] = i;
    radixPass(R , SA12, T + 2, n02, K);
    radixPass(SA12, R , T + 1, n02, K);
    radixPass(R , SA12, T , n02, K);
    int name = 0, c0 = -1, c1 = -1, c2 = -1;

    for( i = 0; i < n02; i++)
    {
        if(T[SA12[i]] != c0 || T[SA12[i] + 1] != c1 || T[SA12[i] + 2] != c2)
        {
            name++; c0 = T[SA12[i]]; c1 = T[SA12[i] + 1]; c2 = T[SA12[i] + 2];
        }
        if(SA12[i] % 3 == 1) { R[SA12[i] / 3] = name; }
        else{ R[SA12[i] / 3 + n0] = name; }
    }
    if(name < n02)
    {
        suffixArray(R, SA12, n02, name);
        for(int i = 0; i < n02; i++) R[SA12[i]] = i + 1;
    }
    else
        for(int i = 0; i < n02; i++) SA12[R[i] - 1] = i;
    for(i = 0, j = 0; i < n02; i++) if(SA12[i] < n0) R0[j++] = 3 * SA12[i];
    radixPass(R0, SA0, T, n0, K);
    for(int p = 0, t = n0 - n1, k = 0; k < n; k++)
    {
        #define GetI() (SA12[t] < n0 ? SA12[t] * 3 + 1 : (SA12[t] - n0) * 3 + 2)
        int i = GetI();
        int j = SA0[p];
        if(SA12[t] < n0 ?
        leq(T[i], R[SA12[t] + n0], T[j], R[j / 3]) : leq(T[i],T[i + 1],R[SA12[t] - n0 + 1], T[j],T[j + 1],R[j / 3 + n0]))
        {
            SA[k] = i; t++;
            if(t == n02)
                for(k++; p < n0; p++, k++) SA[k] = SA0[p];
        }
        else{
            SA[k] = j;
            if(++p == n0)for(k++; t < n02; t++, k++) SA[k] = GetI();
        }
    }
    delete [] R; delete [] SA12; delete [] SA0; delete [] R0;
}

void LCP(int *str)
{
    int i,j,k;
    len=n;
    for(k=i=0;i<len;i++)
    {
        if( rnk[i] == len - 1 ) lcp[ rnk[i] ] = k = 0;
        else
        {
            if( k > 0 )    k--;
            j = sa[ rnk[i] + 1];
            for(;str[i+k] == str[j+k];k++);
            lcp[rnk[i]] = k;
        }
    }
}
int rmq(int id1,int id2)
{
	int ip1,ip2,le,ri,id;
	ip1=rnk[id1];
	ip2=rnk[id2];
	if(ip1<ip2)
	{
		le=ip1;
		ri=ip2-1;
	}
	else
	{
		le=ip2;
		ri=ip1-1;
	}
	id=lg[ri-le+1];
	return min(fk[id][le],fk[id][ri+1-(1<<id)]);
}
void insert(int pos,int idx,int id)
{
	int i,j,s,p,q,mid;
	mid=(vec[idx][id].l+vec[idx][id].r)/2;
	if(vec[idx][id].l==vec[idx][id].r)
	{
		vec[idx][id].max_id=vec[idx][id].l;
		vec[idx][id].cnt++;
	    return;
	}
	if(pos<=mid)
	{
		if(ll[idx][id]<0)
		{
			ll[idx][id]=num_node[idx]++;
			ll[idx].push_back(-1);
			rr[idx].push_back(-1);
			nw.l=vec[idx][id].l;
		    nw.r=mid;
		    nw.cnt=0;
		    vec[idx].push_back(nw);
		}
		insert(pos,idx,ll[idx][id]);
	}
	else
	{
		if(rr[idx][id]<0)
		{
		    rr[idx][id]=num_node[idx]++;
		    ll[idx].push_back(-1);
		    rr[idx].push_back(-1);
		    nw.l=mid+1;
		    nw.r=vec[idx][id].r;
		    nw.cnt=0;
		    vec[idx].push_back(nw);
		}
		insert(pos,idx,rr[idx][id]);
	}
	vec[idx][id].cnt=0;
	vec[idx][id].max_id=-1;
	if(ll[idx][id]>=0)
	{
	   vec[idx][id].cnt=vec[idx][ll[idx][id]].cnt;
	   vec[idx][id].max_id=vec[idx][ll[idx][id]].max_id;
	}
	if(rr[idx][id]>=0)
    {
    	if(vec[idx][id].cnt<vec[idx][rr[idx][id]].cnt)
    	{
	    	vec[idx][id].cnt=vec[idx][rr[idx][id]].cnt;
	    	vec[idx][id].max_id=vec[idx][rr[idx][id]].max_id;
	    }
    }
}
segment_tree query(int left,int right,int idx,int id)
{
	int l=ll[idx][id],r=rr[idx][id];
	segment_tree res,rk;
	res.cnt=0;
	if(left>vec[idx][id].r||right<vec[idx][id].l)
	    return res;
    if(left<=vec[idx][id].l&&right>=vec[idx][id].r)
        return vec[idx][id];
    if(l>=0)
    	res=query(left,right,idx,l);
    if(r>=0)
    {
    	rk=query(left,right,idx,r);
    	if(res.cnt<rk.cnt)
    	  res=rk;
    }
    return res;
}
void solve(int id)
{
	int i,j,s,p,q,ip,ax=0,im,pr;
	im=-1;
	sort(adj[id].begin(),adj[id].end(),cmp);
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i];
		solve(ip);
		assert(sz[ix[ip]]<50000);
		if(ax<sz[ix[ip]])
		{
			ax=sz[ix[ip]];
			im=ix[ip];
		}
	}
	if(ax>0)
		ix[id]=im;
	else
	{
	    ix[id]=cnt++;
		nw.l=0;
    	nw.r=m-1;
	    nw.cnt=0;
	    nw.max_id=-1;
	    num_node[ix[id]]=1;
	    ll[ix[id]].push_back(-1);
	    rr[ix[id]].push_back(-1);
	    vec[ix[id]].push_back(nw);
	}
//	if(id==3155)
	  //  printf("im=%d\n",im);
	pr=qy[id].pl;
    sz[ix[id]]=0;
	for(i=0;i<adj[id].size();i++)
    {
    	ip=adj[id][i];
    	for(j=pr;j<qy[ip].pl;j=nxt[j])
    	{
    	//	assert(pos[j]>0);
    	 //   if(i==3155)
    	  //     printf("%d ",pos[j]);
	    	insert(pos[j]-1,ix[id],0);
    	    sz[ix[id]]++;
		}
		if(ix[ip]!=ix[id])
    	{
    		//assert(pos[qy[ip].pl]>0);
	    	for(;j<=qy[ip].pr;j=nxt[j])
	    	   insert(pos[j]-1,ix[id],0);
			sz[ix[id]]+=sz[ix[ip]];
			vec[ix[ip]].clear();
			ll[ix[ip]].clear();
			rr[ix[ip]].clear();
			sz[ix[ip]]=0;
		}
        pr=nxt[qy[ip].pr];
	}
    for(j=pr;j<=qy[id].pr;j=nxt[j])
    {
    	sz[ix[id]]++;
        insert(pos[j]-1,ix[id],0);
    }
  //  if(i==3155)
    //    printf("\n");
	segment_tree nx=query(qy[id].l,qy[id].r,ix[id],0);
    if(nx.cnt==0)
       nx.max_id=qy[id].l;
    ans[0][id]=nx.max_id+1;
    ans[1][id]=nx.cnt;
    if(pa[id]<0)
    {
    	vec[ix[id]].clear();
    	ll[ix[id]].clear();
    	rr[ix[id]].clear();
    }
}
int main()
{
	int i,j,s,p,q,k;
	gets(str);
	n=strlen(str);
	scanf("%d",&m);
	getchar();
	lg[1]=0;
	for(i=2;i<=600000;i++)
		lg[i]=lg[i/2]+1;
	for(i=0;i<n;i++)
	    num[i]=str[i]-'a'+2;
    num[n++]=1;
	for(i=0;i<m;i++)
	{
		gets(tr);
		sum[i]=n;
		len=strlen(tr);
		for(j=0;j<len;j++)
		    num[n++]=tr[j]-'a'+2;
        num[n++]=0;
	}
	sum[i]=n;
	suffixArray(num,sa,n,27);
	for(i=0;i<n;i++)
		rnk[sa[i]]=i;
	for(i=0;i<n;i++)
	   pos[rnk[i]]=0;
    for(i=0;i<m;i++)
    {
    	for(j=sum[i];j<sum[i+1];j++)
    	   pos[rnk[j]]=i+1;
    }
	LCP(num);
	for(i=0;i<n;i++)
	   fk[0][i]=lcp[i];
    for(k=1;(1<<k)<=n;k++)
       for(i=0;i+(1<<k)<=n;i++)
          fk[k][i]=min(fk[k-1][i],fk[k-1][i+(1<<(k-1))]);
    scanf("%d",&num_q);
     nxt[n]=n;
	 for(i=n;i>0;i--)
     {
     	if(i<n&&pos[i]>0)
     	   nxt[i-1]=i;
  	    else
  	       nxt[i-1]=nxt[i];
     }
     pre[0]=-1;
     for(i=0;i<n-1;i++)
     {
     	if(pos[i]>0)
     	   pre[i+1]=i;
  	    else
  	       pre[i+1]=pre[i];
     }
    for(i=0;i<num_q;i++)
    {
    	scanf("%d%d%d%d",&qy[i].l,&qy[i].r,&qy[i].pl,&qy[i].pr);
    	qy[i].l--;
    	qy[i].r--;
    	qy[i].pl--;
    	qy[i].pr--;
    	int l=rnk[qy[i].pl],low,high,mid;
    	low=l+1;
    	high=n-1;
    	int dx=qy[i].pr-qy[i].pl+1;
		while(low<=high)
    	{
	    	mid=(low+high)>>1;
	    	if(rmq(sa[l],sa[mid])>=dx)
	    	   low=mid+1;
  	        else
  	           high=mid-1;
	    }
	    if(pos[high]>0)
	        qy[i].pr=high;
	    else
	        qy[i].pr=pre[high];
		low=0;
	    high=l-1;
	    while(low<=high)
	    {
    		mid=(low+high)>>1;
    		if(rmq(sa[mid],sa[l])>=dx)
    		   high=mid-1;
 		    else
 		       low=mid+1;
    	}
    	if(pos[low]>0)
        	qy[i].pl=low;
        else
            qy[i].pl=nxt[low];
	}
    cnt=0;
    for(i=0;i<num_q;i++)
    {
    	if(qy[i].pl>qy[i].pr)
    	    continue;
    	x[cnt].flag=-1;
    	x[cnt].id=i;
    	x[cnt++].x=qy[i].pl;
    	x[cnt].flag=1;
    	x[cnt].id=i;
    	x[cnt++].x=qy[i].pr;
    }
    sort(x,x+cnt);
    hs.clear();
    for(i=0;i<num_q;i++)
       pa[i]=-1;
    for(i=0;i<cnt;i++)
    {
   	    now.id=x[i].id;
   	    now.x=qy[now.id].pl;
    	if(x[i].flag<0)
	    {
 		    it=hs.upper_bound(now);
    		if(it!=hs.begin())
    		{
    			it--;
		    	pa[now.id]=it->id;
		    }
	    	hs.insert(now);
	    }
	    else
    		hs.erase(now);
    }
    for(i=0;i<=num_q;i++)
       adj[i].clear();
	memset(ix,-1,sizeof(ix));
	for(i=0;i<num_q;i++)
    {
    	if(pa[i]>=0)
    	  adj[pa[i]].push_back(i);
    }
    for(i=0;i<=num_q;i++)
    {
   	   ll[i].clear();
   	   rr[i].clear();
       vec[i].clear();
    }
    cnt=0;
    memset(ans,0,sizeof(ans));
    for(i=0;i<num_q;i++)
        ans[0][i]=qy[i].l+1;
    for(i=0;i<num_q;i++)
    {
    	if(qy[i].pl>qy[i].pr)
    	   continue;
    	if(pa[i]<0)
    	   solve(i);
    }
    for(i=0;i<num_q;i++)
       printf("%d %d\n",ans[0][i],ans[1][i]);
	return 0;
}
/*
suffixtree
3
suffixtreesareawesome
cartesiantreeisworsethansegmenttree
nyeeheeheee
2
1 3 9 9
1 3 10 10

*/


#include<iostream>
#include<stdio.h>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<set>
#include<assert.h>
using namespace std;
struct segment_tree
{
	int l,r,cnt,max_id;
};
vector<segment_tree>vec[510010];
vector<int>ll[510010],rr[510010];
int num_node[510010],list[510000],cnt_list;
segment_tree nw;
struct query
{
	int l,r,pl,pr;
};
query qy[510000];
bool cmp(int id1,int id2)
{
	return qy[id1].pl<qy[id2].pl;
}
struct pp
{
	int id,x;
	bool operator <(const pp &temp)const
	{
		if(x==temp.x)
		{
			if(qy[id].pr-qy[id].pl==qy[temp.id].pr-qy[temp.id].pl)
		       return id<temp.id;
		    return qy[id].pr-qy[id].pl>qy[temp.id].pr-qy[temp.id].pl;
		}
		return x<temp.x;
	}
};
set<pp>hs;
set<pp>::iterator it;
pp now;
struct xx
{
	int x,flag,id;
	bool operator <(const xx &temp)const
	{
		if(x==temp.x)
		{
		   if(flag==temp.flag)
		   {
		   	   if(qy[id].pr-qy[id].pl==qy[temp.id].pr-qy[temp.id].pl)
		          return id<temp.id;
		       return qy[id].pr-qy[id].pl>qy[temp.id].pr-qy[temp.id].pl;
		   }
		   return flag<temp.flag;
		}
		return x<temp.x;
	}
};
xx x[1100000];
int num_q,cnt;
const int maxn=600001;
char str[555555],tr[55555];
int m,len,n,lg[600001],pa[5010000];
int sa[maxn],rnk[maxn],lcp[maxn],fk[20][maxn];
int num[maxn],sum[55555],pos[600001],nxt[600001],ix[510000],ans[2][510000],pre[600001],sz[510000];
vector<int>adj[510000];
inline bool leq(int a1, int a2, int b1, int b2)
{
    return (a1 < b1 || a1 == b1 && a2 <= b2);
}

inline bool leq(int a1, int a2, int a3, int b1, int b2, int b3)
{
    return(a1 < b1 || a1 == b1 && leq(a2, a3, b2, b3));
}

static void radixPass(int* a, int* b, int* r, int n, int K)
{
    int* c = new int[K + 1];
    int i,sum;
    for(i = 0; i <= K; i++)
        c[i] = 0;
    for(i = 0; i < n; i++)
        c[r[a[i]]]++;
    for(i = 0, sum = 0; i <= K; i++)
    {
        int t = c[i];
        c[i] = sum;
        sum += t;
    }
    for(i = 0; i < n; i++)
        b[c[r[a[i]]]++] = a[i];
    delete [] c;
}

void suffixArray(int* T, int* SA, int n, int K)
{
    int n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3, n02 = n0 + n2;
    int* R = new int[n02 + 3]; R[n02] = R[n02+1] = R[n02 + 2] = 0;
    int* SA12 = new int[n02 + 3]; SA12[n02] = SA12[n02 + 1] = SA12[n02 + 2] = 0;
    int* R0 = new int[n0];
    int* SA0 = new int[n0];
    int i,j;
    for(i = 0, j = 0; i < n + (n0 - n1); i++) if(i % 3 != 0) R[j++] = i;
    radixPass(R , SA12, T + 2, n02, K);
    radixPass(SA12, R , T + 1, n02, K);
    radixPass(R , SA12, T , n02, K);
    int name = 0, c0 = -1, c1 = -1, c2 = -1;

    for( i = 0; i < n02; i++)
    {
        if(T[SA12[i]] != c0 || T[SA12[i] + 1] != c1 || T[SA12[i] + 2] != c2)
        {
            name++; c0 = T[SA12[i]]; c1 = T[SA12[i] + 1]; c2 = T[SA12[i] + 2];
        }
        if(SA12[i] % 3 == 1) { R[SA12[i] / 3] = name; }
        else{ R[SA12[i] / 3 + n0] = name; }
    }
    if(name < n02)
    {
        suffixArray(R, SA12, n02, name);
        for(int i = 0; i < n02; i++) R[SA12[i]] = i + 1;
    }
    else
        for(int i = 0; i < n02; i++) SA12[R[i] - 1] = i;
    for(i = 0, j = 0; i < n02; i++) if(SA12[i] < n0) R0[j++] = 3 * SA12[i];
    radixPass(R0, SA0, T, n0, K);
    for(int p = 0, t = n0 - n1, k = 0; k < n; k++)
    {
        #define GetI() (SA12[t] < n0 ? SA12[t] * 3 + 1 : (SA12[t] - n0) * 3 + 2)
        int i = GetI();
        int j = SA0[p];
        if(SA12[t] < n0 ?
        leq(T[i], R[SA12[t] + n0], T[j], R[j / 3]) : leq(T[i],T[i + 1],R[SA12[t] - n0 + 1], T[j],T[j + 1],R[j / 3 + n0]))
        {
            SA[k] = i; t++;
            if(t == n02)
                for(k++; p < n0; p++, k++) SA[k] = SA0[p];
        }
        else{
            SA[k] = j;
            if(++p == n0)for(k++; t < n02; t++, k++) SA[k] = GetI();
        }
    }
    delete [] R; delete [] SA12; delete [] SA0; delete [] R0;
}

void LCP(int *str)
{
    int i,j,k;
    len=n;
    for(k=i=0;i<len;i++)
    {
        if( rnk[i] == len - 1 ) lcp[ rnk[i] ] = k = 0;
        else
        {
            if( k > 0 )    k--;
            j = sa[ rnk[i] + 1];
            for(;str[i+k] == str[j+k];k++);
            lcp[rnk[i]] = k;
        }
    }
}
int rmq(int id1,int id2)
{
	int ip1,ip2,le,ri,id;
	ip1=rnk[id1];
	ip2=rnk[id2];
	if(ip1<ip2)
	{
		le=ip1;
		ri=ip2-1;
	}
	else
	{
		le=ip2;
		ri=ip1-1;
	}
	id=lg[ri-le+1];
	return min(fk[id][le],fk[id][ri+1-(1<<id)]);
}
void insert(int pos,int idx,int id)
{
	int i,j,s,p,q,mid;
	mid=(vec[idx][id].l+vec[idx][id].r)/2;
	if(vec[idx][id].l==vec[idx][id].r)
	{
		vec[idx][id].max_id=vec[idx][id].l;
		vec[idx][id].cnt++;
	    return;
	}
	if(pos<=mid)
	{
		if(ll[idx][id]<0)
		{
			ll[idx][id]=num_node[idx]++;
			ll[idx].push_back(-1);
			rr[idx].push_back(-1);
			nw.l=vec[idx][id].l;
		    nw.r=mid;
		    nw.cnt=0;
		    vec[idx].push_back(nw);
		}
		insert(pos,idx,ll[idx][id]);
	}
	else
	{
		if(rr[idx][id]<0)
		{
		    rr[idx][id]=num_node[idx]++;
		    ll[idx].push_back(-1);
		    rr[idx].push_back(-1);
		    nw.l=mid+1;
		    nw.r=vec[idx][id].r;
		    nw.cnt=0;
		    vec[idx].push_back(nw);
		}
		insert(pos,idx,rr[idx][id]);
	}
	vec[idx][id].cnt=0;
	vec[idx][id].max_id=-1;
	if(ll[idx][id]>=0)
	{
	   vec[idx][id].cnt=vec[idx][ll[idx][id]].cnt;
	   vec[idx][id].max_id=vec[idx][ll[idx][id]].max_id;
	}
	if(rr[idx][id]>=0)
    {
    	if(vec[idx][id].cnt<vec[idx][rr[idx][id]].cnt)
    	{
	    	vec[idx][id].cnt=vec[idx][rr[idx][id]].cnt;
	    	vec[idx][id].max_id=vec[idx][rr[idx][id]].max_id;
	    }
    }
}
segment_tree query(int left,int right,int idx,int id)
{
	int l=ll[idx][id],r=rr[idx][id];
	segment_tree res,rk;
	res.cnt=0;
	if(left>vec[idx][id].r||right<vec[idx][id].l)
	    return res;
    if(left<=vec[idx][id].l&&right>=vec[idx][id].r)
        return vec[idx][id];
    if(l>=0)
    	res=query(left,right,idx,l);
    if(r>=0)
    {
    	rk=query(left,right,idx,r);
    	if(res.cnt<rk.cnt)
    	  res=rk;
    }
    return res;
}
void solve(int id)
{
	int i,j,s,p,q,ip,ax=0,im,pr;
	im=-1;
	sort(adj[id].begin(),adj[id].end(),cmp);
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i];
		solve(ip);
		if(ax<sz[ix[ip]])
		{
			ax=sz[ix[ip]];
			im=ix[ip];
		}
	}
	if(ax>0)
		ix[id]=im;
	else
	{
		if(cnt_list==0)
	       ix[id]=cnt++;
        else
        {
        	ix[id]=list[cnt_list-1];
        	cnt_list--;
        }
		nw.l=0;
    	nw.r=m-1;
	    nw.cnt=0;
	    nw.max_id=-1;
	    num_node[ix[id]]=1;
	    ll[ix[id]].push_back(-1);
	    rr[ix[id]].push_back(-1);
	    vec[ix[id]].push_back(nw);
	}
	pr=qy[id].pl;
    sz[ix[id]]=0;
	for(i=0;i<adj[id].size();i++)
    {
    	ip=adj[id][i];
    	for(j=pr;j<qy[ip].pl;j=nxt[j])
    	{
	    	insert(pos[j]-1,ix[id],0);
    	    sz[ix[id]]++;
		}
		if(ix[ip]!=ix[id])
    	{
	    	for(;j<=qy[ip].pr;j=nxt[j])
	    	   insert(pos[j]-1,ix[id],0);
			sz[ix[id]]+=sz[ix[ip]];
			vec[ix[ip]].clear();
			ll[ix[ip]].clear();
			rr[ix[ip]].clear();
			sz[ix[ip]]=0;
			list[cnt_list++]=ix[ip];
		}
        pr=nxt[qy[ip].pr];
	}
    for(j=pr;j<=qy[id].pr;j=nxt[j])
    {
    	sz[ix[id]]++;
        insert(pos[j]-1,ix[id],0);
    }
	segment_tree nx=query(qy[id].l,qy[id].r,ix[id],0);
    if(nx.cnt==0)
       nx.max_id=qy[id].l;
    ans[0][id]=nx.max_id+1;
    ans[1][id]=nx.cnt;
    if(pa[id]<0)
    {
    	vec[ix[id]].clear();
    	ll[ix[id]].clear();
    	rr[ix[id]].clear();
    	sz[ix[id]]=0;
    	list[cnt_list++]=ix[id];
    }
}
int main()
{
	int i,j,s,p,q,k;
	gets(str);
	n=strlen(str);
	scanf("%d",&m);
	getchar();
	lg[1]=0;
	for(i=2;i<=600000;i++)
		lg[i]=lg[i/2]+1;
	for(i=0;i<n;i++)
	    num[i]=str[i]-'a'+2;
    num[n++]=1;
	for(i=0;i<m;i++)
	{
		gets(tr);
		sum[i]=n;
		len=strlen(tr);
		for(j=0;j<len;j++)
		    num[n++]=tr[j]-'a'+2;
        num[n++]=0;
	}
	sum[i]=n;
	suffixArray(num,sa,n,27);
	for(i=0;i<n;i++)
		rnk[sa[i]]=i;
	for(i=0;i<n;i++)
	   pos[rnk[i]]=0;
    for(i=0;i<m;i++)
    {
    	for(j=sum[i];j<sum[i+1];j++)
    	   pos[rnk[j]]=i+1;
    }
	LCP(num);
	for(i=0;i<n;i++)
	   fk[0][i]=lcp[i];
    for(k=1;(1<<k)<=n;k++)
       for(i=0;i+(1<<k)<=n;i++)
          fk[k][i]=min(fk[k-1][i],fk[k-1][i+(1<<(k-1))]);
    scanf("%d",&num_q);
     nxt[n]=n;
	 for(i=n;i>0;i--)
     {
     	if(i<n&&pos[i]>0)
     	   nxt[i-1]=i;
  	    else
  	       nxt[i-1]=nxt[i];
     }
     pre[0]=-1;
     for(i=0;i<n-1;i++)
     {
     	if(pos[i]>0)
     	   pre[i+1]=i;
  	    else
  	       pre[i+1]=pre[i];
     }
    for(i=0;i<num_q;i++)
    {
    	scanf("%d%d%d%d",&qy[i].l,&qy[i].r,&qy[i].pl,&qy[i].pr);
    	qy[i].l--;
    	qy[i].r--;
    	qy[i].pl--;
    	qy[i].pr--;
    	int l=rnk[qy[i].pl],low,high,mid;
    	low=l+1;
    	high=n-1;
    	int dx=qy[i].pr-qy[i].pl+1;
		while(low<=high)
    	{
	    	mid=(low+high)>>1;
	    	if(rmq(sa[l],sa[mid])>=dx)
	    	   low=mid+1;
  	        else
  	           high=mid-1;
	    }
	    if(pos[high]>0)
	        qy[i].pr=high;
	    else
	        qy[i].pr=pre[high];
		low=0;
	    high=l-1;
	    while(low<=high)
	    {
    		mid=(low+high)>>1;
    		if(rmq(sa[mid],sa[l])>=dx)
    		   high=mid-1;
 		    else
 		       low=mid+1;
    	}
    	if(pos[low]>0)
        	qy[i].pl=low;
        else
            qy[i].pl=nxt[low];
	}
    cnt=0;
    for(i=0;i<num_q;i++)
    {
    	if(qy[i].pl>qy[i].pr)
    	    continue;
    	x[cnt].flag=-1;
    	x[cnt].id=i;
    	x[cnt++].x=qy[i].pl;
    	x[cnt].flag=1;
    	x[cnt].id=i;
    	x[cnt++].x=qy[i].pr;
    }
    sort(x,x+cnt);
    hs.clear();
    for(i=0;i<num_q;i++)
       pa[i]=-1;
    for(i=0;i<cnt;i++)
    {
   	    now.id=x[i].id;
   	    now.x=qy[now.id].pl;
    	if(x[i].flag<0)
	    {
 		    it=hs.upper_bound(now);
    		if(it!=hs.begin())
    		{
    			it--;
		    	pa[now.id]=it->id;
		    }
	    	hs.insert(now);
	    }
	    else
    		hs.erase(now);
    }
    for(i=0;i<=num_q;i++)
       adj[i].clear();
	memset(ix,-1,sizeof(ix));
	for(i=0;i<num_q;i++)
    {
    	if(pa[i]>=0)
    	  adj[pa[i]].push_back(i);
    }
    for(i=0;i<=num_q;i++)
    {
   	   ll[i].clear();
   	   rr[i].clear();
       vec[i].clear();
    }
    cnt_list=0;
    cnt=0;
    memset(ans,0,sizeof(ans));
    for(i=0;i<num_q;i++)
        ans[0][i]=qy[i].l+1;
	for(i=0;i<num_q;i++)
    {
    	if(qy[i].pl>qy[i].pr)
    	   continue;
    	if(pa[i]<0)
    	   solve(i);
    }
    for(i=0;i<num_q;i++)
       printf("%d %d\n",ans[0][i],ans[1][i]);
	return 0;
}
/*
suffixtree
3
suffixtreesareawesome
cartesiantreeisworsethansegmenttree
nyeeheeheee
2
1 3 9 9
1 3 10 10

*/


#include<iostream>
#include<stdio.h>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<set>
#include<assert.h>
using namespace std;
struct segment_tree
{
	int l,r,cnt,max_id;
};
vector<segment_tree>vec[510010];
vector<int>ll[510010],rr[510010];
int num_node[510010];
segment_tree nw;
struct query
{
	int l,r,pl,pr;
};
query qy[510000];
struct pp
{
	int id,x;
	bool operator <(const pp &temp)const
	{
		if(x==temp.x)
		{
			if(qy[id].pr-qy[id].pl==qy[temp.id].pr-qy[temp.id].pl)
		       return id<temp.id;
		    return qy[id].pr-qy[id].pl>qy[temp.id].pr-qy[temp.id].pl;
		}
		return x<temp.x;
	}
};
set<pp>hs;
set<pp>::iterator it;
pp now;
struct xx
{
	int x,flag,id;
	bool operator <(const xx &temp)const
	{
		if(x==temp.x)
		{
		   if(flag==temp.flag)
		   {
		   	   if(qy[id].pr-qy[id].pl==qy[temp.id].pr-qy[temp.id].pl)
		          return id<temp.id;
		       return qy[id].pr-qy[id].pl>qy[temp.id].pr-qy[temp.id].pl;
		   }
		   return flag<temp.flag;
		}
		return x<temp.x;
	}
};
xx x[1100000];
int num_q,cnt;
const int maxn=600000;
char str[555555],tr[55555];
int m,len,n,lg[600000],pa[5010000];
int sa[maxn],rnk[maxn],lcp[maxn],fk[20][maxn];
int num[maxn],sum[55555],pos[600000],nxt[600000],ix[510000],ans[2][510000],pre[600000],sz[510000];
vector<int>adj[510000];
inline bool leq(int a1, int a2, int b1, int b2)
{
    return (a1 < b1 || a1 == b1 && a2 <= b2);
}

inline bool leq(int a1, int a2, int a3, int b1, int b2, int b3)
{
    return(a1 < b1 || a1 == b1 && leq(a2, a3, b2, b3));
}

static void radixPass(int* a, int* b, int* r, int n, int K)
{
    int* c = new int[K + 1];
    int i,sum;
    for(i = 0; i <= K; i++)
        c[i] = 0;
    for(i = 0; i < n; i++)
        c[r[a[i]]]++;
    for(i = 0, sum = 0; i <= K; i++)
    {
        int t = c[i];
        c[i] = sum;
        sum += t;
    }
    for(i = 0; i < n; i++)
        b[c[r[a[i]]]++] = a[i];
    delete [] c;
}

void suffixArray(int* T, int* SA, int n, int K)
{
    int n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3, n02 = n0 + n2;
    int* R = new int[n02 + 3]; R[n02] = R[n02+1] = R[n02 + 2] = 0;
    int* SA12 = new int[n02 + 3]; SA12[n02] = SA12[n02 + 1] = SA12[n02 + 2] = 0;
    int* R0 = new int[n0];
    int* SA0 = new int[n0];
    int i,j;
    for(i = 0, j = 0; i < n + (n0 - n1); i++) if(i % 3 != 0) R[j++] = i;
    radixPass(R , SA12, T + 2, n02, K);
    radixPass(SA12, R , T + 1, n02, K);
    radixPass(R , SA12, T , n02, K);
    int name = 0, c0 = -1, c1 = -1, c2 = -1;

    for( i = 0; i < n02; i++)
    {
        if(T[SA12[i]] != c0 || T[SA12[i] + 1] != c1 || T[SA12[i] + 2] != c2)
        {
            name++; c0 = T[SA12[i]]; c1 = T[SA12[i] + 1]; c2 = T[SA12[i] + 2];
        }
        if(SA12[i] % 3 == 1) { R[SA12[i] / 3] = name; }
        else{ R[SA12[i] / 3 + n0] = name; }
    }
    if(name < n02)
    {
        suffixArray(R, SA12, n02, name);
        for(int i = 0; i < n02; i++) R[SA12[i]] = i + 1;
    }
    else
        for(int i = 0; i < n02; i++) SA12[R[i] - 1] = i;
    for(i = 0, j = 0; i < n02; i++) if(SA12[i] < n0) R0[j++] = 3 * SA12[i];
    radixPass(R0, SA0, T, n0, K);
    for(int p = 0, t = n0 - n1, k = 0; k < n; k++)
    {
        #define GetI() (SA12[t] < n0 ? SA12[t] * 3 + 1 : (SA12[t] - n0) * 3 + 2)
        int i = GetI();
        int j = SA0[p];
        if(SA12[t] < n0 ?
        leq(T[i], R[SA12[t] + n0], T[j], R[j / 3]) : leq(T[i],T[i + 1],R[SA12[t] - n0 + 1], T[j],T[j + 1],R[j / 3 + n0]))
        {
            SA[k] = i; t++;
            if(t == n02)
                for(k++; p < n0; p++, k++) SA[k] = SA0[p];
        }
        else{
            SA[k] = j;
            if(++p == n0)for(k++; t < n02; t++, k++) SA[k] = GetI();
        }
    }
    delete [] R; delete [] SA12; delete [] SA0; delete [] R0;
}

void LCP(int *str)
{
    int i,j,k;
    len=n;
    for(k=i=0;i<len;i++)
    {
        if( rnk[i] == len - 1 ) lcp[ rnk[i] ] = k = 0;
        else
        {
            if( k > 0 )    k--;
            j = sa[ rnk[i] + 1];
            for(;str[i+k] == str[j+k];k++);
            lcp[rnk[i]] = k;
        }
    }
}
int rmq(int id1,int id2)
{
	int ip1,ip2,le,ri,id;
	ip1=rnk[id1];
	ip2=rnk[id2];
	if(ip1<ip2)
	{
		le=ip1;
		ri=ip2-1;
	}
	else
	{
		le=ip2;
		ri=ip1-1;
	}
	id=lg[ri-le+1];
	return min(fk[id][le],fk[id][ri+1-(1<<id)]);
}
void insert(int pos,int idx,int id)
{
	int i,j,s,p,q,mid;
	mid=(vec[idx][id].l+vec[idx][id].r)/2;
	if(vec[idx][id].l==vec[idx][id].r)
	{
		vec[idx][id].max_id=vec[idx][id].l;
		vec[idx][id].cnt++;
	    return;
	}
	if(pos<=mid)
	{
		if(ll[idx][id]<0)
		{
			ll[idx][id]=num_node[idx]++;
			ll[idx].push_back(-1);
			rr[idx].push_back(-1);
			nw.l=vec[idx][id].l;
		    nw.r=mid;
		    vec[idx].push_back(nw);
		}
		insert(pos,idx,ll[idx][id]);
	}
	else
	{
		if(rr[idx][id]<0)
		{
		    rr[idx][id]=num_node[idx]++;
		    ll[idx].push_back(-1);
		    rr[idx].push_back(-1);
		    nw.l=mid+1;
		    nw.r=vec[idx][id].r;
		    vec[idx].push_back(nw);
		}
		insert(pos,idx,rr[idx][id]);
	}
	vec[idx][id].cnt=0;
	vec[idx][id].max_id=-1;
	if(ll[idx][id]>=0)
	{
	   vec[idx][id].cnt=vec[idx][ll[idx][id]].cnt;
	   vec[idx][id].max_id=vec[idx][ll[idx][id]].max_id;
	}
	if(rr[idx][id]>=0)
    {
    	if(vec[idx][id].cnt<vec[idx][rr[idx][id]].cnt)
    	{
	    	vec[idx][id].cnt=vec[idx][rr[idx][id]].cnt;
	    	vec[idx][id].max_id=vec[idx][rr[idx][id]].max_id;
	    }
    }
}
segment_tree query(int left,int right,int idx,int id)
{
	int l=ll[idx][id],r=rr[idx][id];
	segment_tree res,rk;
	res.cnt=0;
	if(left>vec[idx][id].r||right<vec[idx][id].l)
	    return res;
    if(left<=vec[idx][id].l&&right>=vec[idx][id].r)
        return vec[idx][id];
    if(l>=0)
    	res=query(left,right,idx,l);
    if(r>=0)
    {
    	rk=query(left,right,idx,r);
    	if(res.cnt<rk.cnt)
    	  res=rk;
    }
    return res;
}
void solve(int id)
{
	int i,j,s,p,q,ip,ax=0,im,pr;
	im=-1;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i];
		solve(ip);
		if(ax<sz[ix[ip]])
		{
			ax=sz[ix[ip]];
			im=ix[ip];
		}
		assert(ax>0);
	}
	if(ax>0)
		ix[id]=im;
	else
	{
	    ix[id]=cnt++;
		nw.l=0;
    	nw.r=m-1;
	    nw.cnt=0;
	    nw.max_id=-1;
	    num_node[ix[id]]=1;
	    ll[ix[id]].push_back(-1);
	    rr[ix[id]].push_back(-1);
	    vec[ix[id]].push_back(nw);
	}
	pr=qy[id].pl;
    sz[ix[id]]=0;
	for(i=0;i<adj[id].size();i++)
    {
    	ip=adj[id][i];
    	for(j=pr;j<qy[ip].pl;j=nxt[j])
    	{
	    	insert(pos[j]-1,ix[id],0);
    	    sz[ix[id]]++;
		}
		if(ix[ip]!=ix[id])
    	{
	    	for(;j<qy[ip].pr;j=nxt[j])
	    	   insert(pos[j]-1,ix[id],0);
	        sz[ix[id]]+=sz[ix[ip]];
		}
        pr=nxt[qy[ip].pr];
	}
    for(j=pr;j<=qy[id].pr;j=nxt[j])
    {
    	sz[ix[id]]++;
        insert(pos[j]-1,ix[id],0);
    }
	segment_tree nx=query(qy[id].l,qy[id].r,ix[id],0);
    if(nx.cnt==0)
       nx.max_id=qy[id].l;
    ans[0][id]=nx.max_id+1;
    ans[1][id]=nx.cnt;
}
int main()
{
	int i,j,s,p,q,k;
	gets(str);
	n=strlen(str);
	scanf("%d",&m);
	getchar();
	lg[1]=0;
	for(i=2;i<=600000;i++)
		lg[i]=lg[i/2]+1;
	for(i=0;i<n;i++)
	    num[i]=str[i]-'a'+m+1;
    num[n++]=m;
	for(i=0;i<m;i++)
	{
		gets(tr);
		sum[i]=n;
		len=strlen(tr);
		for(j=0;j<len;j++)
		    num[n++]=tr[j]-'a'+m+1;
        num[n++]=m-i-1;
	}
	sum[i]=n;
	suffixArray(num,sa,n,m+26);
	for(i=0;i<n;i++)
		rnk[sa[i]]=i;
	for(i=0;i<n;i++)
	   pos[rnk[i]]=0;
    for(i=0;i<m;i++)
    {
    	for(j=sum[i];j<sum[i+1];j++)
    	   pos[rnk[j]]=i+1;
    }
	LCP(num);
	for(i=0;i<n;i++)
	   fk[0][i]=lcp[i];
    for(k=1;(1<<k)<=n;k++)
       for(i=0;i+(1<<k)<=n;i++)
          fk[k][i]=min(fk[k-1][i],fk[k-1][i+(1<<(k-1))]);
    scanf("%d",&num_q);
     nxt[n]=n;
	 for(i=n;i>0;i--)
     {
     	if(i<n&&pos[i]>0)
     	   nxt[i-1]=i;
  	    else
  	       nxt[i-1]=nxt[i];
     }
   //  for(i=0;i<n;i++)
    //    printf("nxt[%d]=%d\n",i,nxt[i]);
     pre[0]=-1;
     for(i=0;i<n-1;i++)
     {
     	if(pos[i]>0)
     	   pre[i+1]=pre[i];
  	    else
  	       pre[i+1]=pre[i];
     }
    for(i=0;i<num_q;i++)
    {
    	scanf("%d%d%d%d",&qy[i].l,&qy[i].r,&qy[i].pl,&qy[i].pr);
    	qy[i].l--;
    	qy[i].r--;
    	qy[i].pl--;
    	qy[i].pr--;
    	int l=rnk[qy[i].pl],low,high,mid;
    	low=l;
    	high=n-1;
    	int dx=qy[i].pr-qy[i].pl+1;
		while(low<=high)
    	{
	    	mid=(low+high)>>1;
	    	if(rmq(sa[l],sa[mid])>=dx)
	    	   low=mid+1;
  	        else
  	           high=mid-1;
	    }
	    if(pos[high]>0)
	        qy[i].pr=high;
	    else
	        qy[i].pr=pre[high];
		low=0;
	    high=l-1;
	    while(low<=high)
	    {
    		mid=(low+high)>>1;
    		if(rmq(sa[mid],sa[l])>=dx)
    		   high=mid-1;
 		    else
 		       low=mid+1;
    	}
    	if(pos[low]>0)
        	qy[i].pl=low;
        else
            qy[i].pl=nxt[low];
        if(i==16)
           printf("pl=%d,pr=%d\n",qy[i].pl,qy[i].pr);
	}
    cnt=0;
    for(i=0;i<num_q;i++)
    {
    	if(qy[i].pl>qy[i].pr)
    	    continue;
    	x[cnt].flag=-1;
    	x[cnt].id=i;
    	x[cnt++].x=qy[i].pl;
    	x[cnt].flag=1;
    	x[cnt].id=i;
    	x[cnt++].x=qy[i].pr;
    }
    sort(x,x+cnt);
    hs.clear();
    for(i=0;i<num_q;i++)
       pa[i]=-1;
    for(i=0;i<cnt;i++)
    {
   	    now.id=x[i].id;
   	    now.x=qy[now.id].pl;
    	if(x[i].flag<0)
	    {
 		    it=hs.upper_bound(now);
    		if(it!=hs.begin())
    		{
    			it--;
		    	pa[now.id]=it->id;
		    }
	    	hs.insert(now);
	    }
	    else
	    {
    		hs.erase(now);
    	}
    }
    for(i=0;i<=num_q;i++)
       adj[i].clear();
	memset(ix,-1,sizeof(ix));
	for(i=0;i<num_q;i++)
    {
    	if(pa[i]>=0)
    	  adj[pa[i]].push_back(i);
    }
    for(i=0;i<=num_q;i++)
    {
   	   ll[i].clear();
   	   rr[i].clear();
       vec[i].clear();
    }
    cnt=0;
    memset(ans,0,sizeof(ans));
    for(i=0;i<num_q;i++)
        ans[0][i]=qy[i].l+1;
    for(i=0;i<num_q;i++)
    {
    	if(qy[i].pl>qy[i].pr)
    	   continue;
    	if(pa[i]<0)
    	   solve(i);
    }
    for(i=0;i<num_q;i++)
       printf("%d %d\n",ans[0][i],ans[1][i]);
	return 0;
}
/*
suffixtree
3
suffixtreesareawesome
cartesiantreeisworsethansegmenttree
nyeeheeheee
2
1 3 9 9
1 3 10 10

*/


#include<iostream>
#include<stdio.h>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
struct segment_tree
{
	int l,r,cnt,max_id;
};
vector<segment_tree>vec[510010];
vector<int>ll[510010],rr[510010];
int num_node[510010];
segment_tree nw;
struct query
{
	int l,r,pl,pr;
};
query qy[510000];
struct pp
{
	int id,x;
	bool operator <(const pp &temp)const
	{
		if(x==temp.x)
		{
			if(qy[id].pr-qy[id].pl==qy[temp.id].pr-qy[temp.id].pl)
		       return id<temp.id;
		    return qy[id].pr-qy[id].pl>qy[temp.id].pr-qy[temp.id].pl;
		}
		return x<temp.x;
	}
};
set<pp>hs;
set<pp>::iterator it;
pp now;
struct xx
{
	int x,flag,id;
	bool operator <(const xx &temp)const
	{
		if(x==temp.x)
		{
		   if(flag==temp.flag)
		   {
		   	   if(qy[id].pr-qy[id].pl==qy[temp.id].pr-qy[temp.id].pl)
		          return id<temp.id;
		       return qy[id].pr-qy[id].pl>qy[temp.id].pr-qy[temp.id].pl;
		   }
		   return flag<temp.flag;
		}
		return x<temp.x;
	}
};
xx x[1100000];
int num_q,cnt;
const int maxn=600000;
char str[555555],tr[55555];
int m,len,n,lg[600000],pa[5010000];
int sa[maxn],rnk[maxn],lcp[maxn],fk[20][maxn];
int num[maxn],sum[55555],pos[600000],nxt[600000],ix[510000],ans[2][510000],pre[600000],sz[510000];
vector<int>adj[510000];
inline bool leq(int a1, int a2, int b1, int b2)
{
    return (a1 < b1 || a1 == b1 && a2 <= b2);
}

inline bool leq(int a1, int a2, int a3, int b1, int b2, int b3)
{
    return(a1 < b1 || a1 == b1 && leq(a2, a3, b2, b3));
}

static void radixPass(int* a, int* b, int* r, int n, int K)
{
    int* c = new int[K + 1];
    int i,sum;
    for(i = 0; i <= K; i++)
        c[i] = 0;
    for(i = 0; i < n; i++)
        c[r[a[i]]]++;
    for(i = 0, sum = 0; i <= K; i++)
    {
        int t = c[i];
        c[i] = sum;
        sum += t;
    }
    for(i = 0; i < n; i++)
        b[c[r[a[i]]]++] = a[i];
    delete [] c;
}

void suffixArray(int* T, int* SA, int n, int K)
{
    int n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3, n02 = n0 + n2;
    int* R = new int[n02 + 3]; R[n02] = R[n02+1] = R[n02 + 2] = 0;
    int* SA12 = new int[n02 + 3]; SA12[n02] = SA12[n02 + 1] = SA12[n02 + 2] = 0;
    int* R0 = new int[n0];
    int* SA0 = new int[n0];
    int i,j;
    for(i = 0, j = 0; i < n + (n0 - n1); i++) if(i % 3 != 0) R[j++] = i;
    radixPass(R , SA12, T + 2, n02, K);
    radixPass(SA12, R , T + 1, n02, K);
    radixPass(R , SA12, T , n02, K);
    int name = 0, c0 = -1, c1 = -1, c2 = -1;

    for( i = 0; i < n02; i++)
    {
        if(T[SA12[i]] != c0 || T[SA12[i] + 1] != c1 || T[SA12[i] + 2] != c2)
        {
            name++; c0 = T[SA12[i]]; c1 = T[SA12[i] + 1]; c2 = T[SA12[i] + 2];
        }
        if(SA12[i] % 3 == 1) { R[SA12[i] / 3] = name; }
        else{ R[SA12[i] / 3 + n0] = name; }
    }
    if(name < n02)
    {
        suffixArray(R, SA12, n02, name);
        for(int i = 0; i < n02; i++) R[SA12[i]] = i + 1;
    }
    else
        for(int i = 0; i < n02; i++) SA12[R[i] - 1] = i;
    for(i = 0, j = 0; i < n02; i++) if(SA12[i] < n0) R0[j++] = 3 * SA12[i];
    radixPass(R0, SA0, T, n0, K);
    for(int p = 0, t = n0 - n1, k = 0; k < n; k++)
    {
        #define GetI() (SA12[t] < n0 ? SA12[t] * 3 + 1 : (SA12[t] - n0) * 3 + 2)
        int i = GetI();
        int j = SA0[p];
        if(SA12[t] < n0 ?
        leq(T[i], R[SA12[t] + n0], T[j], R[j / 3]) : leq(T[i],T[i + 1],R[SA12[t] - n0 + 1], T[j],T[j + 1],R[j / 3 + n0]))
        {
            SA[k] = i; t++;
            if(t == n02)
                for(k++; p < n0; p++, k++) SA[k] = SA0[p];
        }
        else{
            SA[k] = j;
            if(++p == n0)for(k++; t < n02; t++, k++) SA[k] = GetI();
        }
    }
    delete [] R; delete [] SA12; delete [] SA0; delete [] R0;
}

void LCP(int *str)
{
    int i,j,k;
    len=n;
    for(k=i=0;i<len;i++)
    {
        if( rnk[i] == len - 1 ) lcp[ rnk[i] ] = k = 0;
        else
        {
            if( k > 0 )    k--;
            j = sa[ rnk[i] + 1];
            for(;str[i+k] == str[j+k];k++);
            lcp[rnk[i]] = k;
        }
    }
}
int rmq(int id1,int id2)
{
	int ip1,ip2,le,ri,id;
	ip1=rnk[id1];
	ip2=rnk[id2];
	if(ip1<ip2)
	{
		le=ip1;
		ri=ip2-1;
	}
	else
	{
		le=ip2;
		ri=ip1-1;
	}
	id=lg[ri-le+1];
	return min(fk[id][le],fk[id][ri+1-(1<<id)]);
}
void insert(int pos,int idx,int id)
{
	int i,j,s,p,q,mid;
	mid=(vec[idx][id].l+vec[idx][id].r)/2;
	if(vec[idx][id].l==vec[idx][id].r)
	{
		vec[idx][id].max_id=vec[idx][id].l;
		vec[idx][id].cnt++;
	    return;
	}
	if(pos<=mid)
	{
		if(ll[idx][id]<0)
		{
			ll[idx][id]=num_node[idx]++;
			ll[idx].push_back(-1);
			rr[idx].push_back(-1);
			nw.l=vec[idx][id].l;
		    nw.r=mid;
		    vec[idx].push_back(nw);
		}
		insert(pos,idx,ll[idx][id]);
	}
	else
	{
		if(rr[idx][id]<0)
		{
		    rr[idx][id]=num_node[idx]++;
		    ll[idx].push_back(-1);
		    rr[idx].push_back(-1);
		    nw.l=mid+1;
		    nw.r=vec[idx][id].r;
		    vec[idx].push_back(nw);
		}
		insert(pos,idx,rr[idx][id]);
	}
	vec[idx][id].cnt=0;
	vec[idx][id].max_id=-1;
	if(ll[idx][id]>=0)
	{
	   vec[idx][id].cnt=vec[idx][ll[idx][id]].cnt;
	   vec[idx][id].max_id=vec[idx][ll[idx][id]].max_id;
	}
	if(rr[idx][id]>=0)
    {
    	if(vec[idx][id].cnt<vec[idx][rr[idx][id]].cnt)
    	{
	    	vec[idx][id].cnt=vec[idx][rr[idx][id]].cnt;
	    	vec[idx][id].max_id=vec[idx][rr[idx][id]].max_id;
	    }
    }
}
segment_tree query(int left,int right,int idx,int id)
{
	int l=ll[idx][id],r=rr[idx][id];
	segment_tree res,rk;
	res.cnt=0;
	if(left>vec[idx][id].r||right<vec[idx][id].l)
	    return res;
    if(left<=vec[idx][id].l&&right>=vec[idx][id].r)
        return vec[idx][id];
    if(l>=0)
    	res=query(left,right,idx,l);
    if(r>=0)
    {
    	rk=query(left,right,idx,r);
    	if(res.cnt<rk.cnt)
    	  res=rk;
    }
    return res;
}
void solve(int id)
{
	int i,j,s,p,q,ip,ax=0,im,pr;
	im=-1;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i];
		solve(ip);
		if(ax<sz[ix[ip]])
		{
			ax=sz[ix[ip]];
			im=ix[ip];
		}
	}
	if(ax>0)
		ix[id]=im;
	else
	{
	    ix[id]=cnt++;
		nw.l=0;
    	nw.r=m-1;
	    nw.cnt=0;
	    nw.max_id=-1;
	    num_node[ix[id]]=1;
	    ll[ix[id]].push_back(-1);
	    rr[ix[id]].push_back(-1);
	    vec[ix[id]].push_back(nw);
	}
	pr=qy[id].pl;
    sz[ix[id]]=0;
	for(i=0;i<adj[id].size();i++)
    {
    	ip=adj[id][i];
    	for(j=pr;j<qy[ip].pl;j=nxt[j])
    	{
	    	insert(pos[j]-1,ix[id],0);
    	    sz[ix[id]]++;
		}
		if(ix[ip]!=ix[id])
    	{
	    	for(;j<qy[ip].pr;j=nxt[j])
	    	   insert(pos[j]-1,ix[id],0);
	        sz[ix[id]]+=sz[ix[ip]];
		}
        pr=nxt[qy[ip].pr];
	}
    for(j=pr;j<=qy[id].pr;j=nxt[j])
    {
    	sz[ix[id]]++;
        insert(pos[j]-1,ix[id],0);
    }
	segment_tree nx=query(qy[id].l,qy[id].r,ix[id],0);
    if(nx.cnt==0)
       nx.max_id=qy[id].l;
    ans[0][id]=nx.max_id+1;
    ans[1][id]=nx.cnt;
}
int main()
{
	int i,j,s,p,q,k;
	gets(str);
	n=strlen(str);
	scanf("%d",&m);
	getchar();
	lg[1]=0;
	for(i=2;i<=600000;i++)
		lg[i]=lg[i/2]+1;
	for(i=0;i<n;i++)
	    num[i]=str[i]-'a'+m+1;
    num[n++]=m;
	for(i=0;i<m;i++)
	{
		gets(tr);
		sum[i]=n;
		len=strlen(tr);
		for(j=0;j<len;j++)
		    num[n++]=tr[j]-'a'+m+1;
        num[n++]=m-i-1;
	}
	sum[i]=n;
	suffixArray(num,sa,n,m+26);
	for(i=0;i<n;i++)
		rnk[sa[i]]=i;
	for(i=0;i<n;i++)
	   pos[rnk[i]]=0;
    for(i=0;i<m;i++)
    {
    	for(j=sum[i];j<sum[i+1];j++)
    	   pos[rnk[j]]=i+1;
    }
	LCP(num);
	for(i=0;i<n;i++)
	   fk[0][i]=lcp[i];
    for(k=1;(1<<k)<=n;k++)
       for(i=0;i+(1<<k)<=n;i++)
          fk[k][i]=min(fk[k-1][i],fk[k-1][i+(1<<(k-1))]);
    scanf("%d",&num_q);
     nxt[n]=n;
	 for(i=n;i>0;i--)
     {
     	if(i<n&&pos[i]>0)
     	   nxt[i-1]=i;
  	    else
  	       nxt[i-1]=nxt[i];
     }
   //  for(i=0;i<n;i++)
    //    printf("nxt[%d]=%d\n",i,nxt[i]);
     pre[0]=-1;
     for(i=0;i<n-1;i++)
     {
     	if(pos[i]>0)
     	   pre[i+1]=pre[i];
  	    else
  	       pre[i+1]=pre[i];
     }
    for(i=0;i<num_q;i++)
    {
    	scanf("%d%d%d%d",&qy[i].l,&qy[i].r,&qy[i].pl,&qy[i].pr);
    	qy[i].l--;
    	qy[i].r--;
    	qy[i].pl--;
    	qy[i].pr--;
    	int l=rnk[qy[i].pl],low,high,mid;
    	low=l;
    	high=n-1;
    	int dx=qy[i].pr-qy[i].pl+1;
		while(low<=high)
    	{
	    	mid=(low+high)>>1;
	    	if(rmq(sa[l],sa[mid])>=dx)
	    	   low=mid+1;
  	        else
  	           high=mid-1;
	    }
	    if(pos[high]>0)
	        qy[i].pr=high;
	    else
	        qy[i].pr=pre[high];
		low=0;
	    high=l-1;
	    while(low<=high)
	    {
    		mid=(low+high)>>1;
    		if(rmq(sa[mid],sa[l])>=dx)
    		   high=mid-1;
 		    else
 		       low=mid+1;
    	}
    	if(pos[low]>0)
        	qy[i].pl=low;
        else
            qy[i].pl=nxt[low];
        //printf("pl=%d,pr=%d\n",qy[i].pl,qy[i].pr);
	}
    cnt=0;
    for(i=0;i<num_q;i++)
    {
    	if(qy[i].pl>qy[i].pr)
    	    continue;
    	x[cnt].flag=-1;
    	x[cnt].id=i;
    	x[cnt++].x=qy[i].pl;
    	x[cnt].flag=1;
    	x[cnt].id=i;
    	x[cnt++].x=qy[i].pr;
    }
    sort(x,x+cnt);
    hs.clear();
    for(i=0;i<num_q;i++)
       pa[i]=-1;
    for(i=0;i<cnt;i++)
    {
   	    now.id=x[i].id;
   	    now.x=qy[now.id].pl;
    	if(x[i].flag<0)
    	{
		    it=hs.upper_bound(now);
    		if(it!=hs.begin())
    		{
    			it--;
		    	pa[now.id]=it->id;
		    }
	    	hs.insert(now);
    	}
	    else
	    {
    		hs.erase(now);
    	}
    }
    for(i=0;i<=num_q;i++)
       adj[i].clear();
	memset(ix,-1,sizeof(ix));
	for(i=0;i<num_q;i++)
    {
    	if(pa[i]>=0)
    	  adj[pa[i]].push_back(i);
    }
    for(i=0;i<=num_q;i++)
    {
   	   ll[i].clear();
   	   rr[i].clear();
       vec[i].clear();
    }
    cnt=0;
    memset(ans,0,sizeof(ans));
    for(i=0;i<num_q;i++)
        ans[0][i]=qy[i].l+1;
    for(i=0;i<num_q;i++)
    {
    	if(qy[i].pl>qy[i].pr)
    	   continue;
    	if(pa[i]<0)
    	   solve(i);
    }
    for(i=0;i<num_q;i++)
       printf("%d %d\n",ans[0][i],ans[1][i]);
	return 0;
}
/*
suffixtree
3
suffixtreesareawesome
cartesiantreeisworsethansegmenttree
nyeeheeheee
2
1 3 9 9
1 3 10 10

*/


#include<iostream>
#include<stdio.h>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<set>
#include<assert.h>
using namespace std;
struct segment_tree
{
	int l,r,cnt,max_id;
};
vector<segment_tree>vec[510010];
vector<int>ll[510010],rr[510010];
int num_node[510010];
segment_tree nw;
struct query
{
	int l,r,pl,pr;
};
query qy[510000];
struct pp
{
	int id,x;
	bool operator <(const pp &temp)const
	{
		if(x==temp.x)
		{
			if(qy[id].pr-qy[id].pl==qy[temp.id].pr-qy[temp.id].pl)
		       return id<temp.id;
		    return qy[id].pr-qy[id].pl>qy[temp.id].pr-qy[temp.id].pl;
		}
		return x<temp.x;
	}
};
set<pp>hs;
set<pp>::iterator it;
pp now;
struct xx
{
	int x,flag,id;
	bool operator <(const xx &temp)const
	{
		if(x==temp.x)
		{
		   if(flag==temp.flag)
		   {
		   	   if(qy[id].pr-qy[id].pl==qy[temp.id].pr-qy[temp.id].pl)
		          return id<temp.id;
		       return qy[id].pr-qy[id].pl>qy[temp.id].pr-qy[temp.id].pl;
		   }
		   return flag<temp.flag;
		}
		return x<temp.x;
	}
};
xx x[1100000];
int num_q,cnt;
const int maxn=600000;
char str[555555],tr[55555];
int m,len,n,lg[600000],pa[5010000];
int sa[maxn],rnk[maxn],lcp[maxn],fk[20][maxn];
int num[maxn],sum[55555],pos[600000],nxt[600000],ix[510000],ans[2][510000],pre[600000],sz[510000];
vector<int>adj[510000];
inline bool leq(int a1, int a2, int b1, int b2)
{
    return (a1 < b1 || a1 == b1 && a2 <= b2);
}

inline bool leq(int a1, int a2, int a3, int b1, int b2, int b3)
{
    return(a1 < b1 || a1 == b1 && leq(a2, a3, b2, b3));
}

static void radixPass(int* a, int* b, int* r, int n, int K)
{
    int* c = new int[K + 1];
    int i,sum;
    for(i = 0; i <= K; i++)
        c[i] = 0;
    for(i = 0; i < n; i++)
        c[r[a[i]]]++;
    for(i = 0, sum = 0; i <= K; i++)
    {
        int t = c[i];
        c[i] = sum;
        sum += t;
    }
    for(i = 0; i < n; i++)
        b[c[r[a[i]]]++] = a[i];
    delete [] c;
}

void suffixArray(int* T, int* SA, int n, int K)
{
    int n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3, n02 = n0 + n2;
    int* R = new int[n02 + 3]; R[n02] = R[n02+1] = R[n02 + 2] = 0;
    int* SA12 = new int[n02 + 3]; SA12[n02] = SA12[n02 + 1] = SA12[n02 + 2] = 0;
    int* R0 = new int[n0];
    int* SA0 = new int[n0];
    int i,j;
    for(i = 0, j = 0; i < n + (n0 - n1); i++) if(i % 3 != 0) R[j++] = i;
    radixPass(R , SA12, T + 2, n02, K);
    radixPass(SA12, R , T + 1, n02, K);
    radixPass(R , SA12, T , n02, K);
    int name = 0, c0 = -1, c1 = -1, c2 = -1;

    for( i = 0; i < n02; i++)
    {
        if(T[SA12[i]] != c0 || T[SA12[i] + 1] != c1 || T[SA12[i] + 2] != c2)
        {
            name++; c0 = T[SA12[i]]; c1 = T[SA12[i] + 1]; c2 = T[SA12[i] + 2];
        }
        if(SA12[i] % 3 == 1) { R[SA12[i] / 3] = name; }
        else{ R[SA12[i] / 3 + n0] = name; }
    }
    if(name < n02)
    {
        suffixArray(R, SA12, n02, name);
        for(int i = 0; i < n02; i++) R[SA12[i]] = i + 1;
    }
    else
        for(int i = 0; i < n02; i++) SA12[R[i] - 1] = i;
    for(i = 0, j = 0; i < n02; i++) if(SA12[i] < n0) R0[j++] = 3 * SA12[i];
    radixPass(R0, SA0, T, n0, K);
    for(int p = 0, t = n0 - n1, k = 0; k < n; k++)
    {
        #define GetI() (SA12[t] < n0 ? SA12[t] * 3 + 1 : (SA12[t] - n0) * 3 + 2)
        int i = GetI();
        int j = SA0[p];
        if(SA12[t] < n0 ?
        leq(T[i], R[SA12[t] + n0], T[j], R[j / 3]) : leq(T[i],T[i + 1],R[SA12[t] - n0 + 1], T[j],T[j + 1],R[j / 3 + n0]))
        {
            SA[k] = i; t++;
            if(t == n02)
                for(k++; p < n0; p++, k++) SA[k] = SA0[p];
        }
        else{
            SA[k] = j;
            if(++p == n0)for(k++; t < n02; t++, k++) SA[k] = GetI();
        }
    }
    delete [] R; delete [] SA12; delete [] SA0; delete [] R0;
}

void LCP(int *str)
{
    int i,j,k;
    len=n;
    for(k=i=0;i<len;i++)
    {
        if( rnk[i] == len - 1 ) lcp[ rnk[i] ] = k = 0;
        else
        {
            if( k > 0 )    k--;
            j = sa[ rnk[i] + 1];
            for(;str[i+k] == str[j+k];k++);
            lcp[rnk[i]] = k;
        }
    }
}
int rmq(int id1,int id2)
{
	int ip1,ip2,le,ri,id;
	ip1=rnk[id1];
	ip2=rnk[id2];
	if(ip1<ip2)
	{
		le=ip1;
		ri=ip2-1;
	}
	else
	{
		le=ip2;
		ri=ip1-1;
	}
	id=lg[ri-le+1];
	return min(fk[id][le],fk[id][ri+1-(1<<id)]);
}
void insert(int pos,int idx,int id)
{
	int i,j,s,p,q,mid;
	mid=(vec[idx][id].l+vec[idx][id].r)/2;
	if(vec[idx][id].l==vec[idx][id].r)
	{
		vec[idx][id].max_id=vec[idx][id].l;
		vec[idx][id].cnt++;
	    return;
	}
	if(pos<=mid)
	{
		if(ll[idx][id]<0)
		{
			ll[idx][id]=num_node[idx]++;
			ll[idx].push_back(-1);
			rr[idx].push_back(-1);
			nw.l=vec[idx][id].l;
		    nw.r=mid;
		    vec[idx].push_back(nw);
		}
		insert(pos,idx,ll[idx][id]);
	}
	else
	{
		if(rr[idx][id]<0)
		{
		    rr[idx][id]=num_node[idx]++;
		    ll[idx].push_back(-1);
		    rr[idx].push_back(-1);
		    nw.l=mid+1;
		    nw.r=vec[idx][id].r;
		    vec[idx].push_back(nw);
		}
		insert(pos,idx,rr[idx][id]);
	}
	vec[idx][id].cnt=0;
	vec[idx][id].max_id=-1;
	if(ll[idx][id]>=0)
	{
	   vec[idx][id].cnt=vec[idx][ll[idx][id]].cnt;
	   vec[idx][id].max_id=vec[idx][ll[idx][id]].max_id;
	}
	if(rr[idx][id]>=0)
    {
    	if(vec[idx][id].cnt<vec[idx][rr[idx][id]].cnt)
    	{
	    	vec[idx][id].cnt=vec[idx][rr[idx][id]].cnt;
	    	vec[idx][id].max_id=vec[idx][rr[idx][id]].max_id;
	    }
    }
}
segment_tree query(int left,int right,int idx,int id)
{
	int l=ll[idx][id],r=rr[idx][id];
	segment_tree res,rk;
	res.cnt=0;
	if(left>vec[idx][id].r||right<vec[idx][id].l)
	    return res;
    if(left<=vec[idx][id].l&&right>=vec[idx][id].r)
        return vec[idx][id];
    if(l>=0)
    	res=query(left,right,idx,l);
    if(r>=0)
    {
    	rk=query(left,right,idx,r);
    	if(res.cnt<rk.cnt)
    	  res=rk;
    }
    return res;
}
void solve(int id)
{
	int i,j,s,p,q,ip,ax=0,im,pr;
	im=-1;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i];
		solve(ip);
		if(ax<sz[ix[ip]])
		{
			ax=sz[ix[ip]];
			im=ix[ip];
		}
		//if(i>0)
	//	{
			int l1=qy[ip].pl,r1=qy[ip].pr;
			assert(l1<=r1);
			int l2=qy[id].pl,r2=qy[id].pr;
			assert(l1>=l2&&r1<=r2);
			for(j=i+1;j<adj[id].size();j++)
			{
				int l2=qy[adj[id][j]].pl,r2=qy[adj[id][j]].pr;
				assert(r1<l2||r2<l1);
			}
	//	}
	}
	if(ax>0)
		ix[id]=im;
	else
	{
	    ix[id]=cnt++;
		nw.l=0;
    	nw.r=m-1;
	    nw.cnt=0;
	    nw.max_id=-1;
	    num_node[ix[id]]=1;
	    ll[ix[id]].push_back(-1);
	    rr[ix[id]].push_back(-1);
	    vec[ix[id]].push_back(nw);
	}
	pr=qy[id].pl;
    sz[ix[id]]=0;
	for(i=0;i<adj[id].size();i++)
    {
    	ip=adj[id][i];
    	for(j=pr;j<qy[ip].pl;j=nxt[j])
    	{
	    	insert(pos[j]-1,ix[id],0);
    	    sz[ix[id]]++;
		}
		if(ix[ip]!=ix[id])
    	{
	    	for(;j<qy[ip].pr;j=nxt[j])
	    	   insert(pos[j]-1,ix[id],0);
	        sz[ix[id]]+=sz[ix[ip]];
		}
        pr=nxt[qy[ip].pr];
	}
    for(j=pr;j<=qy[id].pr;j=nxt[j])
    {
    	sz[ix[id]]++;
        insert(pos[j]-1,ix[id],0);
    }
	segment_tree nx=query(qy[id].l,qy[id].r,ix[id],0);
    if(nx.cnt==0)
       nx.max_id=qy[id].l;
    ans[0][id]=nx.max_id+1;
    ans[1][id]=nx.cnt;
}
int main()
{
	int i,j,s,p,q,k;
	gets(str);
	n=strlen(str);
	scanf("%d",&m);
	getchar();
	lg[1]=0;
	for(i=2;i<=600000;i++)
		lg[i]=lg[i/2]+1;
	for(i=0;i<n;i++)
	    num[i]=str[i]-'a'+m+1;
    num[n++]=m;
	for(i=0;i<m;i++)
	{
		gets(tr);
		sum[i]=n;
		len=strlen(tr);
		for(j=0;j<len;j++)
		    num[n++]=tr[j]-'a'+m+1;
        num[n++]=m-i-1;
	}
	sum[i]=n;
	suffixArray(num,sa,n,m+26);
	for(i=0;i<n;i++)
		rnk[sa[i]]=i;
	for(i=0;i<n;i++)
	   pos[rnk[i]]=0;
    for(i=0;i<m;i++)
    {
    	for(j=sum[i];j<sum[i+1];j++)
    	   pos[rnk[j]]=i+1;
    }
	LCP(num);
	for(i=0;i<n;i++)
	   fk[0][i]=lcp[i];
    for(k=1;(1<<k)<=n;k++)
       for(i=0;i+(1<<k)<=n;i++)
          fk[k][i]=min(fk[k-1][i],fk[k-1][i+(1<<(k-1))]);
    scanf("%d",&num_q);
     nxt[n]=n;
	 for(i=n;i>0;i--)
     {
     	if(i<n&&pos[i]>0)
     	   nxt[i-1]=i;
  	    else
  	       nxt[i-1]=nxt[i];
     }
   //  for(i=0;i<n;i++)
    //    printf("nxt[%d]=%d\n",i,nxt[i]);
     pre[0]=-1;
     for(i=0;i<n-1;i++)
     {
     	if(pos[i]>0)
     	   pre[i+1]=pre[i];
  	    else
  	       pre[i+1]=pre[i];
     }
    for(i=0;i<num_q;i++)
    {
    	scanf("%d%d%d%d",&qy[i].l,&qy[i].r,&qy[i].pl,&qy[i].pr);
    	qy[i].l--;
    	qy[i].r--;
    	qy[i].pl--;
    	qy[i].pr--;
    	int l=rnk[qy[i].pl],low,high,mid;
    	low=l;
    	high=n-1;
    	int dx=qy[i].pr-qy[i].pl+1;
		while(low<=high)
    	{
	    	mid=(low+high)>>1;
	    	if(rmq(sa[l],sa[mid])>=dx)
	    	   low=mid+1;
  	        else
  	           high=mid-1;
	    }
	    if(pos[high]>0)
	        qy[i].pr=high;
	    else
	        qy[i].pr=pre[high];
		low=0;
	    high=l-1;
	    while(low<=high)
	    {
    		mid=(low+high)>>1;
    		if(rmq(sa[mid],sa[l])>=dx)
    		   high=mid-1;
 		    else
 		       low=mid+1;
    	}
    	if(pos[low]>0)
        	qy[i].pl=low;
        else
            qy[i].pl=nxt[low];
        //printf("pl=%d,pr=%d\n",qy[i].pl,qy[i].pr);
	}
    cnt=0;
    for(i=0;i<num_q;i++)
    {
    	if(qy[i].pl>qy[i].pr)
    	    continue;
    	x[cnt].flag=-1;
    	x[cnt].id=i;
    	x[cnt++].x=qy[i].pl;
    	x[cnt].flag=1;
    	x[cnt].id=i;
    	x[cnt++].x=qy[i].pr;
    }
    sort(x,x+cnt);
    hs.clear();
    for(i=0;i<num_q;i++)
       pa[i]=-1;
    for(i=0;i<cnt;i++)
    {
   	    now.id=x[i].id;
   	    now.x=qy[now.id].pl;
    	if(x[i].flag<0)
	    {
 		    it=hs.upper_bound(now);
    		if(it!=hs.begin())
    		{
    			it--;
		    	pa[now.id]=it->id;
		    }
	    	hs.insert(now);
	    }
	    else
	    {
    		hs.erase(now);
    	}
    }
    for(i=0;i<=num_q;i++)
       adj[i].clear();
	memset(ix,-1,sizeof(ix));
	for(i=0;i<num_q;i++)
    {
    	if(pa[i]>=0)
    	  adj[pa[i]].push_back(i);
    }
    for(i=0;i<=num_q;i++)
    {
   	   ll[i].clear();
   	   rr[i].clear();
       vec[i].clear();
    }
    cnt=0;
    memset(ans,0,sizeof(ans));
    for(i=0;i<num_q;i++)
        ans[0][i]=qy[i].l+1;
    for(i=0;i<num_q;i++)
    {
    	if(qy[i].pl>qy[i].pr)
    	   continue;
    	if(pa[i]<0)
    	   solve(i);
    }
    for(i=0;i<num_q;i++)
       printf("%d %d\n",ans[0][i],ans[1][i]);
	return 0;
}
/*
suffixtree
3
suffixtreesareawesome
cartesiantreeisworsethansegmenttree
nyeeheeheee
2
1 3 9 9
1 3 10 10

*/


#include<iostream>
#include<stdio.h>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
struct segment_tree
{
	int l,r,cnt,max_id;
};
vector<segment_tree>vec[510010];
vector<int>ll[510010],rr[510010];
int num_node[510010];
segment_tree nw;
struct query
{
	int l,r,pl,pr;
};
query qy[510000];
struct pp
{
	int id,x;
	bool operator <(const pp &temp)const
	{
		if(x==temp.x)
		   return id<temp.id;
        return x<temp.x;
	}
};
set<pp>hs;
set<pp>::iterator it;
pp now;
struct xx
{
	int x,flag,id;
	bool operator <(const xx &temp)const
	{
		if(x==temp.x)
		{
		   	   if(qy[id].pr-qy[id].pl==qy[temp.id].pr-qy[temp.id].pl)
		   	   {
		   	   	    if(flag==temp.flag)
		   	   	    {
    	   	   			if(flag<0)
    	   	   			   return id<temp.id;
 	   	   			    return id>temp.id;
    	   	   		}
		   	   	    return flag<temp.flag;
		   	   }
			   return qy[id].pr-qy[id].pl>qy[temp.id].pr-qy[temp.id].pl;
		}
		return x<temp.x;
	}
};
xx x[1100000];
int num_q,cnt;
const int maxn=600000;
char str[555555],tr[55555];
int m,len,n,lg[600000],pa[5010000];
int sa[maxn],rnk[maxn],lcp[maxn],fk[20][maxn];
int num[maxn],sum[55555],pos[600000],nxt[600000],ix[510000],ans[2][510000],pre[600000],sz[510000];
vector<int>adj[510000];
inline bool leq(int a1, int a2, int b1, int b2)
{
    return (a1 < b1 || a1 == b1 && a2 <= b2);
}

inline bool leq(int a1, int a2, int a3, int b1, int b2, int b3)
{
    return(a1 < b1 || a1 == b1 && leq(a2, a3, b2, b3));
}

static void radixPass(int* a, int* b, int* r, int n, int K)
{
    int* c = new int[K + 1];
    int i,sum;
    for(i = 0; i <= K; i++)
        c[i] = 0;
    for(i = 0; i < n; i++)
        c[r[a[i]]]++;
    for(i = 0, sum = 0; i <= K; i++)
    {
        int t = c[i];
        c[i] = sum;
        sum += t;
    }
    for(i = 0; i < n; i++)
        b[c[r[a[i]]]++] = a[i];
    delete [] c;
}

void suffixArray(int* T, int* SA, int n, int K)
{
    int n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3, n02 = n0 + n2;
    int* R = new int[n02 + 3]; R[n02] = R[n02+1] = R[n02 + 2] = 0;
    int* SA12 = new int[n02 + 3]; SA12[n02] = SA12[n02 + 1] = SA12[n02 + 2] = 0;
    int* R0 = new int[n0];
    int* SA0 = new int[n0];
    int i,j;
    for(i = 0, j = 0; i < n + (n0 - n1); i++) if(i % 3 != 0) R[j++] = i;
    radixPass(R , SA12, T + 2, n02, K);
    radixPass(SA12, R , T + 1, n02, K);
    radixPass(R , SA12, T , n02, K);
    int name = 0, c0 = -1, c1 = -1, c2 = -1;

    for( i = 0; i < n02; i++)
    {
        if(T[SA12[i]] != c0 || T[SA12[i] + 1] != c1 || T[SA12[i] + 2] != c2)
        {
            name++; c0 = T[SA12[i]]; c1 = T[SA12[i] + 1]; c2 = T[SA12[i] + 2];
        }
        if(SA12[i] % 3 == 1) { R[SA12[i] / 3] = name; }
        else{ R[SA12[i] / 3 + n0] = name; }
    }
    if(name < n02)
    {
        suffixArray(R, SA12, n02, name);
        for(int i = 0; i < n02; i++) R[SA12[i]] = i + 1;
    }
    else
        for(int i = 0; i < n02; i++) SA12[R[i] - 1] = i;
    for(i = 0, j = 0; i < n02; i++) if(SA12[i] < n0) R0[j++] = 3 * SA12[i];
    radixPass(R0, SA0, T, n0, K);
    for(int p = 0, t = n0 - n1, k = 0; k < n; k++)
    {
        #define GetI() (SA12[t] < n0 ? SA12[t] * 3 + 1 : (SA12[t] - n0) * 3 + 2)
        int i = GetI();
        int j = SA0[p];
        if(SA12[t] < n0 ?
        leq(T[i], R[SA12[t] + n0], T[j], R[j / 3]) : leq(T[i],T[i + 1],R[SA12[t] - n0 + 1], T[j],T[j + 1],R[j / 3 + n0]))
        {
            SA[k] = i; t++;
            if(t == n02)
                for(k++; p < n0; p++, k++) SA[k] = SA0[p];
        }
        else{
            SA[k] = j;
            if(++p == n0)for(k++; t < n02; t++, k++) SA[k] = GetI();
        }
    }
    delete [] R; delete [] SA12; delete [] SA0; delete [] R0;
}

void LCP(int *str)
{
    int i,j,k;
    len=n;
    for(k=i=0;i<len;i++)
    {
        if( rnk[i] == len - 1 ) lcp[ rnk[i] ] = k = 0;
        else
        {
            if( k > 0 )    k--;
            j = sa[ rnk[i] + 1];
            for(;str[i+k] == str[j+k];k++);
            lcp[rnk[i]] = k;
        }
    }
}
int rmq(int id1,int id2)
{
	int ip1,ip2,le,ri,id;
	ip1=rnk[id1];
	ip2=rnk[id2];
	if(ip1<ip2)
	{
		le=ip1;
		ri=ip2-1;
	}
	else
	{
		le=ip2;
		ri=ip1-1;
	}
	id=lg[ri-le+1];
	return min(fk[id][le],fk[id][ri+1-(1<<id)]);
}
void insert(int pos,int idx,int id)
{
	int i,j,s,p,q,mid;
	mid=(vec[idx][id].l+vec[idx][id].r)/2;
	if(vec[idx][id].l==vec[idx][id].r)
	{
		vec[idx][id].max_id=vec[idx][id].l;
		vec[idx][id].cnt++;
	    return;
	}
	if(pos<=mid)
	{
		if(ll[idx][id]<0)
		{
			ll[idx][id]=num_node[idx]++;
			ll[idx].push_back(-1);
			rr[idx].push_back(-1);
			nw.l=vec[idx][id].l;
		    nw.r=mid;
		    vec[idx].push_back(nw);
		}
		insert(pos,idx,ll[idx][id]);
	}
	else
	{
		if(rr[idx][id]<0)
		{
		    rr[idx][id]=num_node[idx]++;
		    ll[idx].push_back(-1);
		    rr[idx].push_back(-1);
		    nw.l=mid+1;
		    nw.r=vec[idx][id].r;
		    vec[idx].push_back(nw);
		}
		insert(pos,idx,rr[idx][id]);
	}
	vec[idx][id].cnt=0;
	vec[idx][id].max_id=-1;
	if(ll[idx][id]>=0)
	{
	   vec[idx][id].cnt=vec[idx][ll[idx][id]].cnt;
	   vec[idx][id].max_id=vec[idx][ll[idx][id]].max_id;
	}
	if(rr[idx][id]>=0)
    {
    	if(vec[idx][id].cnt<vec[idx][rr[idx][id]].cnt)
    	{
	    	vec[idx][id].cnt=vec[idx][rr[idx][id]].cnt;
	    	vec[idx][id].max_id=vec[idx][rr[idx][id]].max_id;
	    }
    }
}
segment_tree query(int left,int right,int idx,int id)
{
	int l=ll[idx][id],r=rr[idx][id];
	segment_tree res,rk;
	res.cnt=0;
	if(left>vec[idx][id].r||right<vec[idx][id].l)
	    return res;
    if(left<=vec[idx][id].l&&right>=vec[idx][id].r)
        return vec[idx][id];
    if(l>=0)
    	res=query(left,right,idx,l);
    if(r>=0)
    {
    	rk=query(left,right,idx,r);
    	if(res.cnt<rk.cnt)
    	  res=rk;
    }
    return res;
}
void solve(int id)
{
	int i,j,s,p,q,ip,ax=0,im,pr;
	im=-1;
	for(i=0;i<adj[id].size();i++)
	{
		ip=adj[id][i];
		solve(ip);
		if(ax<sz[ix[ip]])
		{
			ax=sz[ix[ip]];
			im=ix[ip];
		}
	}
	if(ax>0)
		ix[id]=im;
	else
	{
	    ix[id]=cnt++;
		nw.l=0;
    	nw.r=m-1;
	    nw.cnt=0;
	    nw.max_id=-1;
	    num_node[ix[id]]=1;
	    ll[ix[id]].push_back(-1);
	    rr[ix[id]].push_back(-1);
	    vec[ix[id]].push_back(nw);
	}
	pr=qy[id].pl;
	for(i=0;i<adj[id].size();i++)
    {
    	ip=adj[id][i];
    	for(j=pr;j<qy[ip].pl;j=nxt[j])
	    	insert(pos[j]-1,ix[id],0);
    	if(ix[ip]!=ix[id])
    	{
	    	for(;j<qy[ip].pr;j=nxt[j])
	    	   insert(pos[j]-1,ix[id],0);
	    }
        pr=nxt[qy[ip].pr];
	}
    for(j=pr;j<=qy[id].pr;j=nxt[j])
        insert(pos[j]-1,ix[id],0);
	segment_tree nx=query(qy[id].l,qy[id].r,ix[id],0);
    if(nx.cnt==0)
       nx.max_id=qy[id].l;
    ans[0][id]=nx.max_id+1;
    ans[1][id]=nx.cnt;
}
int main()
{
	int i,j,s,p,q,k;
	gets(str);
	n=strlen(str);
	scanf("%d",&m);
	getchar();
	lg[1]=0;
	for(i=2;i<=600000;i++)
		lg[i]=lg[i/2]+1;
	for(i=0;i<n;i++)
	    num[i]=str[i]-'a'+m+1;
    num[n++]=m;
	for(i=0;i<m;i++)
	{
		gets(tr);
		sum[i]=n;
		len=strlen(tr);
		for(j=0;j<len;j++)
		    num[n++]=tr[j]-'a'+m+1;
        num[n++]=m-i-1;
	}
	sum[i]=n;
	suffixArray(num,sa,n,m+26);
	for(i=0;i<n;i++)
		rnk[sa[i]]=i;
	for(i=0;i<n;i++)
	   pos[rnk[i]]=0;
    for(i=0;i<m;i++)
    {
    	for(j=sum[i];j<sum[i+1];j++)
    	   pos[rnk[j]]=i+1;
    }
	LCP(num);
	for(i=0;i<n;i++)
	   fk[0][i]=lcp[i];
    for(k=1;(1<<k)<=n;k++)
       for(i=0;i+(1<<k)<=n;i++)
          fk[k][i]=min(fk[k-1][i],fk[k-1][i+(1<<(k-1))]);
    scanf("%d",&num_q);
     nxt[n]=n;
	 for(i=n;i>0;i--)
     {
     	if(i<n&&pos[i]>0)
     	   nxt[i-1]=i;
  	    else
  	       nxt[i-1]=nxt[i];
     }
   //  for(i=0;i<n;i++)
    //    printf("nxt[%d]=%d\n",i,nxt[i]);
     pre[0]=-1;
     for(i=0;i<n-1;i++)
     {
     	if(pos[i]>0)
     	   pre[i+1]=pre[i];
  	    else
  	       pre[i+1]=pre[i];
     }
    for(i=0;i<num_q;i++)
    {
    	scanf("%d%d%d%d",&qy[i].l,&qy[i].r,&qy[i].pl,&qy[i].pr);
    	qy[i].l--;
    	qy[i].r--;
    	qy[i].pl--;
    	qy[i].pr--;
    	int l=rnk[qy[i].pl],low,high,mid;
    	low=l;
    	high=n-1;
    	int dx=qy[i].pr-qy[i].pl+1;
		while(low<=high)
    	{
	    	mid=(low+high)>>1;
	    	if(rmq(sa[l],sa[mid])>=dx)
	    	   low=mid+1;
  	        else
  	           high=mid-1;
	    }
	    if(pos[high]>0)
	        qy[i].pr=high;
	    else
	        qy[i].pr=pre[high];
		low=0;
	    high=l-1;
	    while(low<=high)
	    {
    		mid=(low+high)>>1;
    		if(rmq(sa[mid],sa[l])>=dx)
    		   high=mid-1;
 		    else
 		       low=mid+1;
    	}
    	if(pos[low]>0)
        	qy[i].pl=low;
        else
            qy[i].pl=nxt[low];

	}
    cnt=0;
    for(i=0;i<num_q;i++)
    {
    	if(qy[i].pl>qy[i].pr)
    	    continue;
    	x[cnt].flag=-1;
    	x[cnt].id=i;
    	x[cnt++].x=qy[i].pl;
    	x[cnt].flag=1;
    	x[cnt].id=i;
    	x[cnt++].x=qy[i].pr;
    }
    sort(x,x+cnt);
    hs.clear();
    for(i=0;i<num_q;i++)
       pa[i]=-1;
    for(i=0;i<cnt;i++)
    {
   	    now.id=x[i].id;
   	    now.x=qy[now.id].pl;
    	if(x[i].flag<0)
	    	hs.insert(now);
	    else
	    {
    		hs.erase(now);
    		it=hs.upper_bound(now);
    		if(it!=hs.begin())
    		{
    			it--;
		    	pa[now.id]=it->id;
		    }
    	}
    }
    for(i=0;i<=num_q;i++)
       adj[i].clear();
	memset(ix,-1,sizeof(ix));
	for(i=0;i<num_q;i++)
    {
    	if(pa[i]>=0)
    	  adj[pa[i]].push_back(i);
    }
    for(i=0;i<=num_q;i++)
    {
   	   ll[i].clear();
   	   rr[i].clear();
       vec[i].clear();
    }
    cnt=0;
    memset(ans,0,sizeof(ans));
    for(i=0;i<num_q;i++)
        ans[0][i]=qy[i].l+1;
    for(i=0;i<num_q;i++)
    {
    	if(qy[i].pl>qy[i].pr)
    	   continue;
    	if(pa[i]<0)
    	   solve(i);
    }
    for(i=0;i<num_q;i++)
       printf("%d %d\n",ans[0][i],ans[1][i]);
	return 0;
}


#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <vector>
#define L ch][0
#define R ch][1
#define mid (l + r) / 2

const int N = 5e5 + 55, LN = 17, M = 2e7 + 72, mmp = 5e5 + 55;

struct pii {
	int x, id;
	bool operator<(const pii &rhs) const {
		return x < rhs.x || (x == rhs.x && id > rhs.id);
	}
};
struct SGT {
	int ch[M][2], nc;
	pii mx[M];
	void up(int x) { x[mx] = std::max(x[L][mx], x[R][mx]); }
	void upd(int &x, int l, int r, int v) {
		if (!x) x = ++nc;
		if (l == r) return x[mx].x++, x[mx].id = l, void();
		if (v <= mid) return upd(x[L], l, mid, v), up(x);
		return upd(x[R], mid + 1, r, v), up(x);
	}
	int mg(int x, int y, int l, int r) {
		if (!x || !y) return x | y;
		int cur = ++nc;
		if (l == r) {
			cur[mx] = {x[mx].x + y[mx].x, x[mx].id};
			return cur;
		}
		cur[L] = mg(x[L], y[L], l, mid);
		cur[R] = mg(x[R], y[R], mid + 1, r);
		return up(cur), cur;
	}
	pii qry(int x, int l, int r, int ql, int qr) {
		if (!x) return {};
		if (ql <= l && r <= qr) return x[mx];
		if (qr <= mid) return qry(x[L], l, mid, ql, qr);
		if (mid < ql) return qry(x[R], mid + 1, r, ql, qr);
		return std::max(qry(x[L], l, mid, ql, qr), qry(x[R], mid + 1, r, ql, qr));
	}
} sgt;

int m;
struct SAM {
	int tr[N][26], link[N], len[N], rt[N], fa[N][LN], nc, last, id;
	std::vector<int> g[N];
	SAM() { nc = last = 1; }
	void ins(int c) {
		int cur = ++nc, p = last, q, cl;
		sgt.upd(cur[rt], 1, m, id);
		cur[len] = p[len] + 1;
		for (; p && !(q = p[tr][c]); p = p[link]) p[tr][c] = cur;
		if (!p)
			cur[link] = 1;
		else if (p[len] + 1 == q[len])
			cur[link] = q;
		else {
			cl = ++nc, cl[len] = p[len] + 1, cl[link] = q[link];
			memcpy(cl[tr], q[tr], sizeof *tr);
			for (; p && p[tr][c] == q; p = p[link]) p[tr][c] = cl;
			q[link] = cur[link] = cl;
		}
		last = cur;
	}
	void operator+=(char *s) {
		int n = strlen(s);
		last = 1, id++;
		for (int i = 0; i < n; i++) ins(s[i] - 97);
	}
	void dfs(int x) {
		for (int nx : x[g]) {
			nx[fa][0] = x;
			for (int i = 1; i < LN; i++) nx[fa][i] = nx[fa][i - 1][fa][i - 1];
			dfs(nx);
			x[rt] = sgt.mg(x[rt], nx[rt], 1, m);
		}
	}
	void build() {
		for (int i = 2; i <= nc; i++) i[link][g].push_back(i);
		dfs(1);
	}
	void exec(char *s, std::vector<int> &v, std::vector<int> &pt) {
		int n = strlen(s), x = 1, l = 0;
		for (int i = 0; i < n; i++) {
			int nx = s[i] - 'a';
			if (x[tr][nx])
				l++, x = x[tr][nx];
			else {
				while (x > 1 && !x[tr][nx]) x = x[link];
				if (x[tr][nx])
					l = x[len] + 1, x = x[tr][nx];
				else
					l = 0;
			}
			v.push_back(l);
			pt.push_back(x);
		}
	}
	int get(int x, int l) {
		for (int i = LN - 1; i >= 0; i--)
			if (x[fa][i][len] >= l) x = x[fa][i];
		return x;
	}
} sam;

std::vector<int> g[N], len, pt;
int q, a, b, c, d;
char s[mmp], t[N];
int main() {
	scanf("%s%d", s, &m);
	for (int i = 1; i <= m; i++) {
		scanf("%s", t);
		sam += t;
	}
	sam.exec(s, len, pt);
	assert(sgt.nc < M);	 // wdnmd
	assert(sam.nc < N);	 // wdnmd
	sam.build();
	scanf("%d", &q);
	for (int i = 1; i <= q; i++) {
		scanf("%d%d%d%d", &a, &b, &c, &d);

		if (d - c + 1 > len[d - 1]) {
			printf("%d 0\n", a);
			continue;
		}
		int p = sam.get(pt[d - 1], d - c + 1);
		pii ans = sgt.qry(p[sam.rt], 1, m, a, b);
		if (!ans.x) ans.id = a;
		printf("%d %d\n", ans.id, ans.x);
	}
}


#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#define L ch][0
#define R ch][1
#define mid (l + r) / 2

const int N = 2e5 + 52, LN = 17, M = 2e7 + 72, mmp = 5e5 + 55;

struct pii {
	int x, id;
	bool operator<(const pii &rhs) const {
		return x < rhs.x || (x == rhs.x && id > rhs.id);
	}
};
struct SGT {
	int ch[M][2], nc;
	pii mx[M];
	void up(int x) { x[mx] = std::max(x[L][mx], x[R][mx]); }
	void upd(int &x, int l, int r, int v) {
		if (!x) x = ++nc;
		if (l == r) return x[mx].x++, x[mx].id = l, void();
		if (v <= mid) return upd(x[L], l, mid, v), up(x);
		return upd(x[R], mid + 1, r, v), up(x);
	}
	int mg(int x, int y, int l, int r) {
		if (!x || !y) return x | y;
		int cur = ++nc;
		if (l == r) {
			cur[mx] = {x[mx].x + y[mx].x, x[mx].id};
			return cur;
		}
		cur[L] = mg(x[L], y[L], l, mid);
		cur[R] = mg(x[R], y[R], mid + 1, r);
		return up(cur), cur;
	}
	pii qry(int x, int l, int r, int ql, int qr) {
		if (!x) return {};
		if (ql <= l && r <= qr) return x[mx];
		if (qr <= mid) return qry(x[L], l, mid, ql, qr);
		if (mid < ql) return qry(x[R], mid + 1, r, ql, qr);
		return std::max(qry(x[L], l, mid, ql, qr), qry(x[R], mid + 1, r, ql, qr));
	}
} sgt;

int m;
struct SAM {
	int tr[N][26], link[N], len[N], rt[N], fa[N][LN], nc, last, id;
	std::vector<int> g[N];
	SAM() { nc = last = 1; }
	void ins(int c) {
		int cur = ++nc, p = last, q, cl;
		sgt.upd(cur[rt], 1, m, id);
		cur[len] = p[len] + 1;
		for (; p && !(q = p[tr][c]); p = p[link]) p[tr][c] = cur;
		if (!p)
			cur[link] = 1;
		else if (p[len] + 1 == q[len])
			cur[link] = q;
		else {
			cl = ++nc, cl[len] = p[len] + 1, cl[link] = q[link];
			memcpy(cl[tr], q[tr], sizeof *tr);
			for (; p && p[tr][c] == q; p = p[link]) p[tr][c] = cl;
			q[link] = cur[link] = cl;
		}
		last = cur;
	}
	void operator+=(char *s) {
		int n = strlen(s);
		last = 1, id++;
		for (int i = 0; i < n; i++) ins(s[i] - 97);
	}
	void dfs(int x) {
		for (int nx : x[g]) {
			nx[fa][0] = x;
			for (int i = 1; i < LN; i++) nx[fa][i] = nx[fa][i - 1][fa][i - 1];
			dfs(nx);
			x[rt] = sgt.mg(x[rt], nx[rt], 1, m);
		}
	}
	void build() {
		for (int i = 2; i <= nc; i++) i[link][g].push_back(i);
		dfs(1);
	}
	void exec(char *s, std::vector<int> &v, std::vector<int> &pt) {
		int n = strlen(s), x = 1, l = 0;
		for (int i = 0; i < n; i++) {
			int nx = s[i] - 'a';
			if (x[tr][nx])
				l++, x = x[tr][nx];
			else {
				while (x > 1 && !x[tr][nx]) x = x[link];
				if (x[tr][nx])
					l = x[len] + 1, x = x[tr][nx];
				else
					l = 0;
			}
			v.push_back(l);
			pt.push_back(x);
		}
	}
	int get(int x, int l) {
		for (int i = LN - 1; i >= 0; i--)
			if (x[fa][i][len] >= l) x = x[fa][i];
		return x;
	}
} sam;

std::vector<int> g[N], len, pt;
int q, a, b, c, d;
char s[mmp], t[N];
int main() {
	scanf("%s%d", s, &m);
	for (int i = 1; i <= m; i++) {
		scanf("%s", t);
		sam += t;
	}
	sam.exec(s, len, pt);
	sam.build();
	scanf("%d", &q);
	for (int i = 1; i <= q; i++) {
		scanf("%d%d%d%d", &a, &b, &c, &d);

		if (d - c + 1 > len[d - 1]) {
			printf("%d 0\n", a);
			continue;
		}
		int p = sam.get(pt[d - 1], d - c + 1);
		pii ans = sgt.qry(p[sam.rt], 1, m, a, b);
		if (!ans.x) ans.id = a;
		printf("%d %d\n", ans.id, ans.x);
	}
}


#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#define L ch][0
#define R ch][1
#define mid (l + r) / 2

const int N = 2e5 + 52, LN = 17, M = 2e7 + 72;

struct pii {
	int x, id;
	bool operator<(const pii &rhs) const {
		return x < rhs.x || (x == rhs.x && id > rhs.id);
	}
};
struct SGT {
	int ch[M][2], nc;
	pii mx[M];
	void up(int x) { x[mx] = std::max(x[L][mx], x[R][mx]); }
	void upd(int &x, int l, int r, int v) {
		if (!x) x = ++nc;
		if (l == r) return x[mx].x++, x[mx].id = l, void();
		if (v <= mid) return upd(x[L], l, mid, v), up(x);
		return upd(x[R], mid + 1, r, v), up(x);
	}
	int mg(int x, int y, int l, int r) {
		if (!x || !y) return x | y;
		int cur = ++nc;
		if (l == r) {
			cur[mx] = {x[mx].x + y[mx].x, x[mx].id};
			return cur;
		}
		cur[L] = mg(x[L], y[L], l, mid);
		cur[R] = mg(x[R], y[R], mid + 1, r);
		return up(cur), cur;
	}
	pii qry(int x, int l, int r, int ql, int qr) {
		if (!x) return {};
		if (ql <= l && r <= qr) return x[mx];
		if (qr <= mid) return qry(x[L], l, mid, ql, qr);
		if (mid < ql) return qry(x[R], mid + 1, r, ql, qr);
		return std::max(qry(x[L], l, mid, ql, qr), qry(x[R], mid + 1, r, ql, qr));
	}
} sgt;

int m;
struct SAM {
	int tr[N][26], link[N], len[N], rt[N], fa[N][LN], nc, last, id;
	std::vector<int> g[N];
	SAM() { nc = last = 1; }
	void ins(int c) {
		int cur = ++nc, p = last, q, cl;
		sgt.upd(cur[rt], 1, m, id);
		cur[len] = p[len] + 1;
		for (; p && !(q = p[tr][c]); p = p[link]) p[tr][c] = cur;
		if (!p)
			cur[link] = 1;
		else if (p[len] + 1 == q[len])
			cur[link] = q;
		else {
			cl = ++nc, cl[len] = p[len] + 1, cl[link] = q[link];
			memcpy(cl[tr], q[tr], sizeof *tr);
			for (; p && p[tr][c] == q; p = p[link]) p[tr][c] = cl;
			q[link] = cur[link] = cl;
		}
		last = cur;
	}
	void operator+=(char *s) {
		int n = strlen(s);
		last = 1, id++;
		for (int i = 0; i < n; i++) ins(s[i] - 97);
	}
	void dfs(int x) {
		for (int nx : x[g]) {
			nx[fa][0] = x;
			for (int i = 1; i < LN; i++) nx[fa][i] = nx[fa][i - 1][fa][i - 1];
			dfs(nx);
			x[rt] = sgt.mg(x[rt], nx[rt], 1, m);
		}
	}
	void build() {
		for (int i = 2; i <= nc; i++) i[link][g].push_back(i);
		dfs(1);
	}
	void exec(char *s, std::vector<int> &v, std::vector<int> &pt) {
		int n = strlen(s), x = 1, l = 0;
		for (int i = 0; i < n; i++) {
			int nx = s[i] - 'a';
			if (x[tr][nx])
				l++, x = x[tr][nx];
			else {
				while (x > 1 && !x[tr][nx]) x = x[link];
				if (x[tr][nx])
					l = x[len] + 1, x = x[tr][nx];
				else
					l = 0;
			}
			v.push_back(l);
			pt.push_back(x);
		}
	}
	int get(int x, int l) {
		for (int i = LN - 1; i >= 0; i--)
			if (x[fa][i][len] >= l) x = x[fa][i];
		return x;
	}
} sam;

std::vector<int> g[N], len, pt;
int q, a, b, c, d;
char s[N], t[N];
int main() {
	scanf("%s%d", s, &m);
	for (int i = 1; i <= m; i++) {
		scanf("%s", t);
		sam += t;
	}
	sam.exec(s, len, pt);
	sam.build();
	scanf("%d", &q);
	for (int i = 1; i <= q; i++) {
		scanf("%d%d%d%d", &a, &b, &c, &d);

		if (d - c + 1 > len[d - 1]) {
			printf("%d 0\n", a);
			continue;
		}
		int p = sam.get(pt[d - 1], d - c + 1);
		pii ans = sgt.qry(p[sam.rt], 1, m, a, b);
		if (!ans.x) ans.id = a;
		printf("%d %d\n", ans.id, ans.x);
	}
} //nmd


#include<bits/stdc++.h>
using namespace std;
const int MAXN = 5e5 + 5;
const int MAXLOG = 20;
const int MAXP = 1.2e6 + 5;
const int MAXQ = 1.2e7 + 5;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct info {int pos, cnt; };
void chkmax(info &x, info y) {
	if (x.cnt < y.cnt) x = y;
	else if (x.cnt == y.cnt && x.pos > y.pos) x = y;
}
struct SegmentTree {
	struct Node {
		int lc, rc;
		info Max;
		bool leaf;
	} a[MAXQ];
	int size, n;
	void init(int x) {
		n = x;
		size = 0;
	}
	void update(int root) {
		a[root].Max = (info) {n, 0};
		if (a[root].lc) chkmax(a[root].Max, a[a[root].lc].Max);
		if (a[root].rc) chkmax(a[root].Max, a[a[root].rc].Max);
	}
	void modify(int &root, int l, int r, int pos) {
		if (root == 0) root = ++size;
		if (l == r) {
			a[root].Max.pos = l;
			a[root].Max.cnt++;
			a[root].leaf = true;
			return;
		}
		int mid = (l + r) / 2;
		if (mid >= pos) modify(a[root].lc, l, mid, pos);
		else modify(a[root].rc, mid + 1, r, pos);
		update(root);
	}
	void modify(int &root, int val) {
		return modify(root, 1, n, val);
	}
	int merge(int x, int y) {
		if (x == 0 || y == 0) return x + y;
		if (a[x].leaf) {
			a[x].Max.cnt += a[y].Max.cnt;
			return x;
		}
		a[x].lc = merge(a[x].lc, a[y].lc);
		a[x].rc = merge(a[x].rc, a[y].rc);
		update(x);
		return x;
	}
	void join(int &to, int from) {
		to = merge(to, from);
	}
	info query(int root, int l, int r, int ql, int qr) {
		if (root == 0) return (info) {ql, 0};
		if (l == ql && r == qr) return a[root].Max;
		info ans = (info) {n, 0};
		int mid = (l + r) / 2;
		if (mid >= ql) chkmax(ans, query(a[root].lc, l, mid, ql, min(mid, qr)));
		if (mid + 1 <= qr) chkmax(ans, query(a[root].rc, mid + 1, r, max(mid + 1, ql), qr));
		return ans;
	}
	info query(int root, int l, int r) {
		return query(root, 1, n, l, r);
	}
} ST;
struct SuffixAutomaton {
	struct Node {
		int child[26], parent[MAXLOG];
		int father, depth, root;
		vector <int> l, r, home;
	} a[MAXP];
	vector <int> t[MAXP];
	int n, m, q, home[MAXN];
	int root, last, size;
	info ans[MAXN];
	char s[MAXN];
	int newnode(int depth) {
		a[size].depth = depth;
		return size++;
	}
	void extend(int ch) {
		int p = last;
		if (a[p].child[ch] != 0) {
			int q = a[p].child[ch];
			if (a[p].depth + 1 == a[q].depth) last = q;
			else {
				int np = newnode(a[p].depth + 1);
				while (a[p].child[ch] == q) {
					a[p].child[ch] = np;
					p = a[p].father;
				}
				a[np].father = a[q].father;
				a[q].father = np;
				memcpy(a[np].child, a[q].child, sizeof(a[q].child));
				last = np;
			}
		} else {
			int np = newnode(a[p].depth + 1);
			while (a[p].child[ch] == 0) {
				a[p].child[ch] = np;
				p = a[p].father;
			}
			if (a[p].child[ch] == np) a[last = np].father = root;
			else {
				int q = a[p].child[ch];
				if (a[p].depth + 1 == a[q].depth) a[last = np].father = q;
				else {
					int nq = newnode(a[p].depth + 1);
					a[nq].father = a[q].father;
					a[q].father = a[np].father = nq;
					memcpy(a[nq].child, a[q].child, sizeof(a[q].child));
					while (a[p].child[ch] == q) {
						a[p].child[ch] = nq;
						p = a[p].father;
					}
					last = np;
				}
			}
		}
	}
	void init() {
		scanf("\n%s", s + 1);
		n = strlen(s + 1);
		size = 0;
		last = root = newnode(0);
		for (int i = 1; i <= n; i++) {
			extend(s[i] - 'a');
			home[i] = last;
		}
		read(m);
		ST.init(m);
		for (int i = 1; i <= m; i++) {
			scanf("\n%s", s + 1);
			int len = strlen(s + 1);
			last = root;
			for (int j = 1; j <= len; j++) {
				extend(s[j] - 'a');
				ST.modify(a[last].root, i);
			}
		}
		for (int i = 1; i < size; i++) {
			a[i].parent[0] = a[i].father;
			t[a[i].father].push_back(i);
		}
		for (int p = 1; p < MAXLOG; p++)
		for (int i = 0; i < size; i++)
			a[i].parent[p] = a[a[i].parent[p - 1]].parent[p - 1];
	}
	void storequery(int num, int pl, int pr, int l, int r) {
		int len = r - l + 1, pos = home[r];
		for (int i = MAXLOG - 1; i >= 0; i--)
			if (a[a[pos].parent[i]].depth >= len) pos = a[pos].parent[i];
		a[pos].l.push_back(pl);
		a[pos].r.push_back(pr);
		a[pos].home.push_back(num);
	}
	void work(int root) {
		for (unsigned i = 0; i < t[root].size(); i++) {
			work(t[root][i]);
			ST.join(a[root].root, a[t[root][i]].root);
		}
		for (unsigned i = 0; i < a[root].l.size(); i++)
			ans[a[root].home[i]] = ST.query(a[root].root, a[root].l[i], a[root].r[i]);
	}
	void calc(int x) {
		q = x; work(root);
		for (int i = 1; i <= q; i++)
			write(ans[i].pos), putchar(' '), writeln(ans[i].cnt);
	}
} SAM;
int main() {
	SAM.init();
	int q; read(q);
	for (int i = 1; i <= q; i++) {
		int l, r, pl, pr;
		read(l), read(r), read(pl), read(pr);
		SAM.storequery(i, l, r, pl, pr);
	}
	SAM.calc(q);
	return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>

template <typename Tp>Tp Max(const Tp &a, const Tp &b) {return a > b ? a : b;}
template <typename Tp>Tp Min(const Tp &a, const Tp &b) {return a < b ? a : b;}

template <typename Tp>void Read(Tp &x) {
    Tp in = 0, f = 1; char ch = getchar();
    while(ch<'0' || ch>'9') {if(ch=='-') f = -1; ch = getchar();}
    while(ch>='0' && ch<='9') {in = in * 10+ch-'0'; ch = getchar();}
    x = in * f;
}

const int SN = 1200000 + 10;

const int SM = SN * 22;

const int ST = 50000 + 10;

int ch[SN][27], fail[SN], sta[SN], d[SN], len[SN], end[SN], f[SN][21], S, last, TIME, n, m;

char s[SN], h[ST];

namespace Seg {

    int sum[SM], max[SM], lson[SM], rson[SM], root[SM], SIZE;

    void pushup(int rt) {

	if(sum[lson[rt]] >= sum[rson[rt]])
	    sum[rt] = sum[lson[rt]], max[rt] = max[lson[rt]];
	else sum[rt] = sum[rson[rt]], max[rt] = max[rson[rt]];

    }

    void Modify(int pos, int l, int r, int &rt) {

	if(!rt) rt = ++SIZE;

	if(l == r) {
	    max[rt] = l, sum[rt]++;
	    return ;
	}

	int mid = (l + r) >> 1;

	if(pos <= mid) Modify(pos, l, mid, lson[rt]);
	else Modify(pos, mid + 1, r, rson[rt]);

	pushup(rt);
    }

    int Merge(int x, int y, int l, int r) {

	if(!x || !y) return x + y;

	if(l == r) {
	    int now = ++SIZE;
	    max[now] = l, sum[now] = sum[x] + sum[y];
	    return now;
	}

	int mid = (l + r) >> 1;

	int now = ++SIZE;

	lson[now] = Merge(lson[x], lson[y], l, mid);
	rson[now] = Merge(rson[x], rson[y], mid + 1, r);

	pushup(now);

	return now;
    }

    void Query(int QL, int QR, int l, int r, int rt, int &A, int &B) {

	if(QL <= l && QR >= r) {
	    if(sum[rt] > A) A = sum[rt], B = max[rt];
	    else if(sum[rt] == A && max[rt] <= B) B = max[rt];
	    return ;
	}

	int mid = (l + r) >> 1;

	if(QL <= mid) Query(QL, QR, l, mid, lson[rt], A, B);
	if(QR > mid) Query(QL, QR, mid + 1, r, rson[rt], A, B);

    }

}

using namespace Seg;

void Insert(int x, int num) {

    int now = ++TIME, p = last, to = s[x] - 'a';

    if(s[x] == '#') to = 26;
    else if(num != 0) Modify(num, 1, m, root[now]);

    end[x] = now;

    last = now, len[now] = len[p] + 1;

    for( ; p && !ch[p][to]; p = fail[p]) ch[p][to] = now;

    if(!p) fail[now] = S;
    else {

	int q = ch[p][to];

	if(len[q] == len[p] + 1) {
	    fail[now] = q;
	    return ;
	}

	int Nq = ++TIME;

	memcpy(ch[Nq], ch[q], sizeof ch[q]);

	fail[Nq] = fail[q], len[Nq] = len[p] + 1;

	fail[now] = fail[q] = Nq;

	for( ; p && ch[p][to] == q; p = fail[p]) ch[p][to] = Nq;

    }

}

int main() {

    int l, r, M, pl, pr, q, top;

    S = last = TIME = 1;

    scanf("%s", s + 1);

    n = strlen(s + 1);

    Read(m);

    for(int i = 1; i <= m; i++) {
	scanf("%s", h + 1);
	s[++n] = '#';
	M = strlen(h + 1);
	for(int j = 1; j <= M; j++) s[++n] = h[j];
    }

    for(int i = 1, num = 0; i <= n; i++) {
	Insert(i, num);
	if(s[i] == '#') num++;
    }

    for(int i = 1; i <= TIME; i++) d[fail[i]]++, f[i][0] = fail[i];

    for(int j = 1; j <= 20; j++)
	for(int i = 1; i <= TIME; i++)
	    f[i][j] = f[f[i][j - 1]][j - 1];

    for(int i = 1; i <= TIME; i++)
	if(!d[i]) sta[++top] = i;

    while(top) {

	int now = sta[top--];

	root[fail[now]] = Merge(root[fail[now]], root[now], 1, m);

	if(!(--d[fail[now]])) sta[++top] = fail[now];

    }

    Read(q);

    while(q--) {

	Read(pl), Read(pr), Read(l), Read(r);

	int K = r - l + 1;

	int now = end[r];

	for(int j = 20; j >= 0; j--)
	    if(len[f[now][j]] >= K) now = f[now][j];

	int max = 0x3f3f3f3f, sum = 0;

	Query(pl, pr, 1, m, root[now], sum, max);

	if(sum != 0)
	    printf("%d %d\n", max, sum);
	else printf("%d %d\n", pl, sum);
    }

    return 0;
}


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 1111111
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
struct SAM
{
	struct Node
	{
		int son[26];
		int ff,len;
	}t[MAX];
	int last,tot;
	void init(){last=tot=1;}
	void extend(int c)
	{
		int p=last,np=++tot;last=np;
		t[np].len=t[p].len+1;
		while(p&&!t[p].son[c])t[p].son[c]=np,p=t[p].ff;
		if(!p)t[np].ff=1;
		else
		{
			int q=t[p].son[c];
			if(t[q].len==t[p].len+1)t[np].ff=q;
			else
			{
				int nq=++tot;
				t[nq]=t[q];
				t[nq].len=t[p].len+1;
				t[q].ff=t[np].ff=nq;
				while(p&&t[p].son[c]==q)t[p].son[c]=nq,p=t[p].ff;
			}
		}
	}
}SAM;

int n,m,f[22][MAX];
struct Data{int v,p;}ans[MAX];
bool operator<(Data a,Data b){return (a.v<b.v)||(a.v==b.v&&a.p>b.p);}
struct SegmentTree{int ls,rs;Data v;}t[MAX<<4];
int Tot,rt[MAX];
struct query{int l,r,pl,pr;}q[MAX];
char S[MAX],T[MAX];
void Modify(int &x,int l,int r,int p)
{
	if(!x)x=++Tot;
	if(l==r){t[x].v.v++;t[x].v.p=p;return;}
	int mid=(l+r)>>1;
	if(p<=mid)Modify(t[x].ls,l,mid,p);
	else Modify(t[x].rs,mid+1,r,p);
	t[x].v=max(t[t[x].ls].v,t[t[x].rs].v);
}
void Merge(int &x,int y)
{
	if(!x||!y){x|=y;return;}
	if(!t[x].ls&&!t[x].rs){t[x].v.v+=t[y].v.v;return;}
	Merge(t[x].ls,t[y].ls);Merge(t[x].rs,t[y].rs);
	t[x].v=max(t[t[x].ls].v,t[t[x].rs].v);
}
Data Query(int x,int l,int r,int L,int R)
{
	if(L==l&&r==R)return t[x].v;
	int mid=(l+r)>>1;
	if(R<=mid)return Query(t[x].ls,l,mid,L,R);
	if(L>mid)return Query(t[x].rs,mid+1,r,L,R);
	return max(Query(t[x].ls,l,mid,L,mid),Query(t[x].rs,mid+1,r,mid+1,R));
}

struct Link
{
	struct Line{int v,next;}e[MAX];
	int h[MAX],cnt;
	void Add(int u,int v){e[++cnt]=(Line){v,h[u]};h[u]=cnt;}
}Par,Qy,Aw;

void dfs(int u)
{
	for(int i=Par.h[u];i;i=Par.e[i].next)
		dfs(Par.e[i].v),Merge(rt[u],rt[Par.e[i].v]);
	for(int i=Aw.h[u];i;i=Aw.e[i].next)
		ans[Aw.e[i].v]=Query(rt[u],1,m,q[Aw.e[i].v].l,q[Aw.e[i].v].r);
}

int main()
{
	scanf("%s",S+1);n=strlen(S+1);
	m=read();SAM.init();
	for(int i=1;i<=m;++i)
	{
		SAM.last=1;scanf("%s",T+1);
		for(int j=1,l=strlen(T+1);j<=l;++j)
			SAM.extend(T[j]-97),Modify(rt[SAM.last],1,m,i);
	}
	int Q=read();
	for(int i=1;i<=Q;++i)
	{
		q[i]=(query){read(),read(),read(),read()};
		Qy.Add(q[i].pr,i);
	}
	for(int i=2;i<=SAM.tot;++i)Par.Add(f[0][i]=SAM.t[i].ff,i);
	for(int i=1;i<22;++i)
		for(int j=1;j<=SAM.tot;++j)f[i][j]=f[i-1][f[i-1][j]];
	for(int i=1,nw=1,len=0;i<=n;++i)
	{
		int c=S[i]-97;
		while(nw&&!SAM.t[nw].son[c])nw=SAM.t[nw].ff,len=SAM.t[nw].len;
		if(!nw){nw=1,len=0;continue;}
		nw=SAM.t[nw].son[c];len+=1;
		for(int j=Qy.h[i];j;j=Qy.e[j].next)
		{
			int v=Qy.e[j].v,u=nw;
			if(len<q[v].pr-q[v].pl+1)continue;
			for(int k=21;~k;--k)
				if(SAM.t[f[k][u]].len>=q[v].pr-q[v].pl+1)u=f[k][u];
			Aw.Add(u,v);
		}
	}
	dfs(1);
	for(int i=1;i<=Q;++i)
	{
		if(!ans[i].v)ans[i].p=q[i].l;
		printf("%d %d\n",ans[i].p,ans[i].v);
	}
	return 0;
}


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 1111111
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
struct SAM
{
	struct Node
	{
		int son[26];
		int ff,len;
	}t[MAX];
	int last,tot;
	void init(){last=tot=1;}
	void extend(int c)
	{
		int p=last,np=++tot;last=np;
		t[np].len=t[p].len+1;
		while(p&&!t[p].son[c])t[p].son[c]=np,p=t[p].ff;
		if(!p)t[np].ff=1;
		else
		{
			int q=t[p].son[c];
			if(t[q].len==t[p].len+1)t[np].ff=q;
			else
			{
				int nq=++tot;
				t[nq]=t[q];
				t[nq].len=t[p].len+1;
				t[q].ff=t[np].ff=nq;
				while(p&&t[p].son[c]==q)t[p].son[c]=nq,p=t[p].ff;
			}
		}
	}
}SAM;

int n,m,f[22][MAX];
struct Data{int v,p;}ans[MAX];
bool operator<(Data a,Data b){return (a.v<b.v)||(a.v==b.v&&a.p>b.p);}
struct SegmentTree{int ls,rs;Data v;}t[MAX<<5];
int Tot,rt[MAX];
struct query{int l,r,pl,pr;}q[MAX];
char S[MAX],T[MAX];
void Modify(int &x,int l,int r,int p)
{
	if(!x)x=++Tot;
	if(l==r){t[x].v.v++;t[x].v.p=p;return;}
	int mid=(l+r)>>1;
	if(p<=mid)Modify(t[x].ls,l,mid,p);
	else Modify(t[x].rs,mid+1,r,p);
	t[x].v=max(t[t[x].ls].v,t[t[x].rs].v);
}
void Merge(int &x,int y)
{
	if(!x||!y){x|=y;return;}
	if(!t[x].ls&&!t[x].rs){t[x].v.v+=t[y].v.v;return;}
	Merge(t[x].ls,t[y].ls);Merge(t[x].rs,t[y].rs);
	t[x].v=max(t[t[x].ls].v,t[t[x].rs].v);
}
Data Query(int x,int l,int r,int L,int R)
{
	if(L==l&&r==R)return t[x].v;
	int mid=(l+r)>>1;
	if(R<=mid)return Query(t[x].ls,l,mid,L,R);
	if(L>mid)return Query(t[x].rs,mid+1,r,L,R);
	return max(Query(t[x].ls,l,mid,L,mid),Query(t[x].rs,mid+1,r,mid+1,R));
}

struct Link
{
	struct Line{int v,next;}e[MAX];
	int h[MAX],cnt;
	void Add(int u,int v){e[++cnt]=(Line){v,h[u]};h[u]=cnt;}
}Par,Qy,Aw;

void dfs(int u)
{
	for(int i=Par.h[u];i;i=Par.e[i].next)
		dfs(Par.e[i].v),Merge(rt[u],rt[Par.e[i].v]);
	for(int i=Aw.h[u];i;i=Aw.e[i].next)
		ans[Aw.e[i].v]=Query(rt[u],1,m,q[Aw.e[i].v].l,q[Aw.e[i].v].r);
}

int main()
{
	scanf("%s",S+1);n=strlen(S+1);
	m=read();SAM.init();
	for(int i=1;i<=m;++i)
	{
		SAM.last=1;scanf("%s",T+1);
		for(int j=1,l=strlen(T+1);j<=l;++j)
			SAM.extend(T[j]-97),Modify(rt[SAM.last],1,m,i);
	}
	int Q=read();
	for(int i=1;i<=Q;++i)
	{
		q[i]=(query){read(),read(),read(),read()};
		Qy.Add(q[i].pr,i);
	}
	for(int i=2;i<=SAM.tot;++i)Par.Add(f[0][i]=SAM.t[i].ff,i);
	for(int i=1;i<22;++i)
		for(int j=1;j<=SAM.tot;++j)f[i][j]=f[i-1][f[i-1][j]];
	for(int i=1,nw=1,len=0;i<=n;++i)
	{
		int c=S[i]-97;
		while(nw&&!SAM.t[nw].son[c])nw=SAM.t[nw].ff,len=SAM.t[nw].len;
		if(!nw){nw=1,len=0;continue;}
		nw=SAM.t[nw].son[c];len+=1;
		for(int j=Qy.h[i];j;j=Qy.e[j].next)
		{
			int v=Qy.e[j].v,u=nw;
			if(len<q[v].pr-q[v].pl+1)continue;
			for(int k=21;~k;--k)
				if(SAM.t[f[k][u]].len>=q[v].pr-q[v].pl+1)u=f[k][u];
			Aw.Add(u,v);
		}
	}
	dfs(1);
	for(int i=1;i<=Q;++i)
	{
		if(!ans[i].v)ans[i].p=q[i].l;
		printf("%d %d\n",ans[i].p,ans[i].v);
	}
	return 0;
}