#include "bits/stdc++.h"
using namespace std;
#ifndef LOCAL
#define endl '\n'
#endif

#define fr(i, a, b) for(int i = a; i <= b; i++)
#define rf(i, a, b) for(int i = a; i >= b; i--)
#define pf push_front
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)x.size()
#define lb lower_bound
#define ub upper_bound

typedef long long ll;
typedef long double f80;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

int pct(int x) { return __builtin_popcount(x); }
int pct(ll x) { return __builtin_popcountll(x); }
int bt(int x) { return 31 - __builtin_clz(x); } // floor(log2(x))
int bt(ll x) { return 63 - __builtin_clzll(x); } // floor(log2(x))
int cdiv(int a, int b) { return a / b + !(a < 0 || a % b == 0); }
ll cdiv(ll a, ll b) { return a / b + !(a < 0 || a % b == 0); }
int nxt_C(int x) { int c = x & -x, r = x + c; return (((r ^ x) >> 2) / c) | r; }
ll nxt_C(ll x) { ll c = x & -x, r = x + c; return (((r ^ x) >> 2) / c) | r; }

vector<int> get_bits(int mask) {
	vector<int> bb;
	while(mask) { int b = bt(mask); bb.pb(b); mask ^= (1 << b); }
	reverse(all(bb));
	return bb;
}

int get_mask(vector<int> v) {
	int mask = 0;
	for(int x : v) { mask ^= (1 << x); }
	return mask;
}

template<typename T>
void uniq(vector<T> &v) { sort(all(v)); v.resize(unique(all(v)) - v.begin()); }
// template<typename T>
// void leftShift(vector<T> &v, ll k) { k %= sz(v); if(k < 0) k += sz(v); rotate(v.begin(), v.begin() + k, v.end()); }
// template<typename T>
// void rightShift(vector<T> &v, ll k) { leftShift(v, sz(v) - k); }

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

ll rand(ll l, ll r){
	uniform_int_distribution<ll> uid(l, r);
	return uid(rng);
}

void sc() {}

template <typename Head, typename... Tail>
void sc(Head &H, Tail &... T) { cin >> H; sc(T...); }

#ifdef LOCAL
#define debug(...) cerr << "[L:" << __LINE__ << "][" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

// #ifndef LOCAL
// string to_string(__int128 x) {
// 	string s = "";
// 	bool neg = 0;
// 	if(x < 0) { s += "-"; neg = 1; x = -x; }
// 	if(!x) s += '0';
// 	while(x) {
// 		int rem = x % 10;
// 		s += to_string(rem);
// 		x /= 10;
// 	}
// 	reverse(s.begin() + neg, s.end());
// 	return s;
// }
// #endif

const int mod = 1e9 + 7; // 998244353;

int pwr(int a,ll b) {
	int ans = 1;
	while(b) {
		if(b & 1) ans = (ans * 1LL * a) % mod;
		a = (a * 1LL * a) % mod;
		b >>= 1;
	}
	return ans;
}

/*
	Lookout for overflows!!
	Check array sizes!!
	Clear before test cases!!
	Use the correct modulo!!
	Check for corner cases!!
	Are you forgetting something?!
	Read problem statement carefully!!!
*/

struct state {
    int len, link;
    map<char, int> next;
};
const int MAXLEN = 6e5 + 5;

int cnt[2 * MAXLEN];
int id[2 * MAXLEN];
int gn[MAXLEN];

state st[MAXLEN * 2];
int sz = 1, last;
void sa_init() {
    st[1].len = 0;
    st[1].link = -1;
    sz++;
    last = 1;
}
void sa_extend(char c, int idx, int pos) {
    int cur = sz++;
    st[cur].len = st[last].len + 1;
    int p = last;
    while (p != -1 && !st[p].next.count(c)) {
        st[p].next[c] = cur;
        p = st[p].link;
    }
    if (p == -1) {
        st[cur].link = 1;
    } else {
        int q = st[p].next[c];
        if (st[p].len + 1 == st[q].len) {
            st[cur].link = q;
        } else {
            int clone = sz++;
            st[clone].len = st[p].len + 1;
            st[clone].next = st[q].next;
            st[clone].link = st[q].link;
            while (p != -1 && st[p].next[c] == q) {
                st[p].next[c] = clone;
                p = st[p].link;
            }
            st[q].link = st[cur].link = clone;
        }
    }
    last = cur;
    id[cur] = idx;
    gn[pos] = cur;
}

/*
	Fill all the ...
	Set the Identity element.
	Set the template variable type carefully.
*/
template<typename T>
class Segtree_Without_Lazy {
	struct node {
		T val;
	};

	// Variables
	int n;
	vector<node> tr;
	T Id;

	// Operations
	inline T op(T a, T b) {
		return max(a, b);
	}
	inline node merge(node a, node b) {
		node ans;
		ans.val = op(a.val, b.val);
		return ans;
	}

	// Private Functions
	void build(int nd, int s, int e) {
		if(s == e) {
            tr[nd].val = {0, -s};
            return;
		}
		int m = (s + e) >> 1;
		build(nd << 1, s, m);
		build(nd << 1 | 1, m + 1, e);
		tr[nd] = merge(tr[nd << 1], tr[nd << 1 | 1]);
	}

	void upd(int idx, int x, int nd, int s, int e) {
		if(s == e) {
    		tr[nd].val.fi += x; return;
		}
		int m = (s + e) >> 1;
		if(idx <= m)
			upd(idx, x, nd << 1, s, m);
		else
			upd(idx, x, nd << 1 | 1, m + 1, e);
		tr[nd] = merge(tr[nd << 1], tr[nd << 1 | 1]);
	}

	T query(int l, int r, int nd, int s, int e) {
		if(s > r || e < l) return Id;
		if(l <= s && e <= r) return tr[nd].val;
		int m = (s + e) >> 1;
		return op(query(l, r, nd << 1, s, m), query(l, r, nd << 1 | 1, m + 1, e));
	}

	void print(int l,int r,int nd,int s,int e, vector<T> &v) {
		if(s > r || e < l) return;
		if(s == e) {
			v.push_back(tr[nd].val);
			return;
		}
		int m = (s + e) >> 1;
		print(l, r, nd << 1, s, m, v);
		print(l, r, nd << 1 | 1, m + 1, e, v);
	}

public:
	// Constructor
	Segtree_Without_Lazy(int nn) : n(nn), Id({0, -1e9}), tr(4 * nn) {
        build(1, 1, nn);
    }

	// Functions
	void upd(int idx, int val) {
		upd(idx, val, 1, 1, n);
	}

	T query(int l,int r) {
		if(l > r) return Id;
		return query(l, r, 1, 1, n);
	}

	void print(int l,int r) {
		vector<T> v;
		print(l, r, 1, 1, n, v);
		debug(v);
	}
};

vector<int> g[2 * MAXLEN];

Segtree_Without_Lazy<pii> seg(5e4 + 5);

const int LOGN = 21;
const int N = 2 * MAXLEN;
int dp[LOGN][N];
int S[N];

pii ans[N];
int str[N], en[N], ver[N], tt;

void pre(int u, int p) {
    str[u] = ++tt;
    ver[tt] = u;
    S[u] = 1;
    dp[0][u] = p;
    for(int v : g[u]) {
        pre(v, u);
        S[u] += S[v];
    }
    en[u] = tt;
}

int go(int u, int l) {
    for(int k = LOGN - 1; k >= 0; k--) {
        if(dp[k][u] && st[dp[k][u]].len >= l) u = dp[k][u];
    }
    return u;
}

vector<tuple<int,int,int>> queries[N];

void dfs(int v, int p, bool keep){
    int mx = -1, bigChild = -1;
    for(auto u : g[v])
       if(S[u] > mx)
          mx = S[u], bigChild = u;
    for(auto u : g[v])
        if(u != bigChild)
            dfs(u, v, 0);
    if(bigChild != -1) dfs(bigChild, v, 1);
    for(auto u : g[v])
        if(u != bigChild)
            for(int p = str[u]; p <= en[u]; p++)
                if(id[ver[p]])
                    seg.upd(id[ver[p]], 1);
    if(id[v])
        seg.upd(id[v], 1);
    for(auto x : queries[v]) {
        int l = get<0>(x), r = get<1>(x), idx = get<2>(x);
        ans[idx] = seg.query(l, r);
    }
    if(!keep)
        for(int p = str[v]; p <= en[v]; p++)
            if(id[ver[p]])
	            seg.upd(id[ver[p]], -1);
}

void solve() {
	string s;
    sc(s);
    sa_init();
    int pc = 0;
    // string tot = "";
    fr(i, 0, sz(s) - 1) {
        sa_extend(s[i], 0, pc++);
        // tot += s[i];
    }
    int m;
    sc(m);
    fr(i, 1, m) {
        string p;
        sc(p);
        sa_extend('#', 0, pc++);
        // tot += '#';
        for(char ch : p) {
            sa_extend(ch, i, pc++);
            // tot += ch;
        }
    }
    fr(i, 2, sz - 1) g[st[i].link].pb(i);
    pre(1, 0);
    fr(k, 1, LOGN - 1) {
        fr(i, 1, sz - 1) {
            dp[k][i] = dp[k - 1][dp[k - 1][i]];
        }
    }
    int q;
    sc(q);
    fr(i, 1, q) {
        int l, r, pl, pr;
        sc(l, r, pl, pr);
        int u = gn[pr - 1];
        int v = go(u, pr - pl + 1);
        queries[v].eb(l, r, i);
    }
    dfs(1, 0, 1);
    fr(i, 1, q) {
        cout << -ans[i].se << " " << ans[i].fi << endl;
    }
}

int main() {
	ios :: sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
	// cin >> t;
	for(int tt = 1; tt <= t; tt++) {
		solve();
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for (int i=(a);i<=(b);++i)
#define ROF(i,a,b) for (int i=(a);i>=(b);--i)
typedef long long ll;
inline int read(){
	int x=0,f=1; char ch=getchar();
	while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
	while (isdigit(ch)) { x=x*10+ch-'0'; ch=getchar(); }
	return x*f;
}

const int MAXN=500005,MAXM=50004;
namespace SAM{
	struct Node{
		int next[26],fail,len;
		void init(){ fail=-1; len=0; memset(next,-1,sizeof(next)); }
	}x[MAXM<<1];
	int size,last,type[MAXM<<1],pos[MAXN],lcs[MAXN];
	void init(){ size=last=0; x[size++].init(); }
	int newnode(){ x[size].init(); return size++; }
	void add(int c,int t){
		int p=newnode(),tmp=last;
		x[p].len=x[last].len+1;
		for (;~tmp&&!~x[tmp].next[c];tmp=x[tmp].fail) x[tmp].next[c]=p;
		if (!~tmp) x[p].fail=0;
		else {
			int q=x[tmp].next[c];
			if (x[tmp].len+1==x[q].len) x[p].fail=q;
			else {
				int np=newnode();
				x[np]=x[q]; x[np].len=x[tmp].len+1; x[p].fail=x[q].fail=np;
				for (;~tmp&&x[tmp].next[c]==q;tmp=x[tmp].fail) x[tmp].next[c]=np;
				type[np]=0;
			}
		}
		last=p;
		type[p]=t;
	}
	void walk(char s[]){
		int n=strlen(s+1),now=0,len=0;
		FOR(i,1,n) {
			for (;~now&&!~x[now].next[s[i]-'a'];now=x[now].fail);
			if (!~now) now=len=0;
			else len=min(len,x[now].len)+1,now=x[now].next[s[i]-'a'];
			pos[i]=now; lcs[i]=len;
			//printf("(%d,%d)%c",pos[i],lcs[i]," \n"[i==n]);
		}
	}
	void print(){
		FOR(i,0,size-1) {
			printf("node[%d]: len=%d fail=%d\n",i,x[i].len,x[i].fail);
			FOR(j,0,2) printf("%c%d%c",'a'+j,x[i].next[j]," \n"[j==2]);
		}
	}
};
char s[MAXN],t[MAXN];
int n,m,q,fa[MAXN][15];
int u[MAXM<<1],esize;
struct edge{ int v,nt; }e[MAXM<<1];
void clear(){ memset(u,-1,sizeof(u)); esize=0; }
void addEdge(int i,int j){
	//printf("%d %d\n",i,j);
	e[esize]=(edge){j,u[i]}; u[i]=esize++;
}
void dfs1(int x,int y){
	fa[x][0]=y;
	FOR(i,1,14) fa[x][i]=fa[fa[x][i-1]][i-1];
	for (int i=u[x];~i;i=e[i].nt) {
		int v=e[i].v;
		dfs1(v,x);
	}
}
pair<int,int> ans[MAXN];
struct Data{ int l,r,i; };
vector <Data> Q[MAXM<<1];
int rt[MAXM<<1],treesize;
struct treenode{ int l,r,max,x; }tr[4000005];
void treeins(int &x,int l,int r,int k){
	if (x==0) {
		x=++treesize;
		tr[x].l=tr[x].r=tr[x].max=0;
	}
	if (l==r) {
		tr[x].max++,tr[x].x=l;
		return;
	}
	int mid=(l+r)/2;
	if (k<=mid) treeins(tr[x].l,l,mid,k);
	else treeins(tr[x].r,mid+1,r,k);
	if (tr[tr[x].l].max>=tr[tr[x].r].max) tr[x].max=tr[tr[x].l].max,tr[x].x=tr[tr[x].l].x;
	else tr[x].max=tr[tr[x].r].max,tr[x].x=tr[tr[x].r].x;
}
void treemerge(int &x,int y,int l,int r){
	if (!x||!y) { x=x+y; return; }
	if (l==r) {
		tr[x].max+=tr[y].max;
		return;
	}
	int mid=(l+r)/2;
	treemerge(tr[x].l,tr[y].l,l,mid);
	treemerge(tr[x].r,tr[y].r,mid+1,r);
	if (tr[tr[x].l].max>=tr[tr[x].r].max) tr[x].max=tr[tr[x].l].max,tr[x].x=tr[tr[x].l].x;
	else tr[x].max=tr[tr[x].r].max,tr[x].x=tr[tr[x].r].x;
}
pair<int,int> treequery(int x,int l,int r,int L,int R){
	if (!x) return make_pair(0,L);
	if (L<=l&&r<=R) return make_pair(tr[x].max,tr[x].x);
	int mid=(l+r)/2;
	pair<int,int> ans1,ans2; ans1=ans2=make_pair(0,L);
	if (L<=mid) ans1=treequery(tr[x].l,l,mid,L,R);
	if (mid<R) ans2=treequery(tr[x].r,mid+1,r,L,R);
	if (ans1.first>=ans2.first) return ans1;
	return ans2;
}
void treeprint(int x,int l,int r){
	if (!x) return;
	printf("(%d,%d,%d,[%d %d])",x,tr[x].max,tr[x].x,l,r);
	if (l==r) return;
	putchar('{');
	int mid=(l+r)/2;
	treeprint(tr[x].l,l,mid);
	treeprint(tr[x].r,mid+1,r);
	putchar('}');
}
void dfs2(int x){
	rt[x]=0;
	//printf("%d type=%d\n",x,SAM::type[x]);
	if (SAM::type[x]) treeins(rt[x],1,m,SAM::type[x]);
	//treeprint(rt[x],1,m); puts("");
	for (int i=u[x];~i;i=e[i].nt) {
		int v=e[i].v;
		dfs2(v);
		treemerge(rt[x],rt[v],1,m);
		//treeprint(rt[x],1,m); puts("");
	}
	for (int i=0;i<(int)Q[x].size();++i) ans[Q[x][i].i]=treequery(rt[x],1,m,Q[x][i].l,Q[x][i].r);
}
int main(){
	scanf("%s",s+1); n=strlen(s+1);
	SAM::init();
	m=read();
	FOR(i,1,m) {
		scanf("%s",t+1); q=strlen(t+1);
		SAM::last=0;
		FOR(j,1,q) SAM::add(t[j]-'a',i);
	}
	clear();
	FOR(i,1,SAM::size-1) addEdge(SAM::x[i].fail,i);
	dfs1(0,0);
	SAM::walk(s);
	//SAM::print();
	q=read();
	FOR(i,1,q) {
		int l=read(),r=read(),pl=read(),pr=read();
		if (pr-pl+1>SAM::lcs[pr]) { ans[i]=make_pair(0,l); continue; }
		int now=SAM::pos[pr];
		ROF(k,14,0)
		if (SAM::x[fa[now][k]].len>=pr-pl+1) now=fa[now][k];
		//printf("i=%d now=%d nowlen=%d\n",i,now,SAM::x[now].len);
		if (now&&SAM::x[now].len>=pr-pl+1) Q[now].push_back((Data){l,r,i});
		else ans[i]=make_pair(0,l);
	}
	treesize=0; dfs2(0);
	FOR(i,1,q) printf("%d %d\n",ans[i].second,ans[i].first);

	return 0;
}

/*
suffixtree
3
suffixtreesareawesome
cartesiantreeisworsethansegmenttree
nyeeheeheee
2
1 2 1 10
1 3 9 10

cbcbbaba
6
aba
a
bbcba
b
abc
ac
1
3 5 1 7

caccc
4
bbb
abb
bccac
baacc
1
3 4 1 4

*/


#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for (int i=(a);i<=(b);++i)
#define ROF(i,a,b) for (int i=(a);i>=(b);--i)
typedef long long ll;
inline int read(){
	int x=0,f=1; char ch=getchar();
	while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
	while (isdigit(ch)) { x=x*10+ch-'0'; ch=getchar(); }
	return x*f;
}

const int MAXN=500005,MAXM=50004;
namespace SAM{
	struct Node{
		int next[26],fail,len;
		void init(){ fail=-1; len=0; memset(next,-1,sizeof(next)); }
	}x[MAXM<<1];
	int size,last,type[MAXM<<1],pos[MAXN];
	void init(){ size=last=0; x[size++].init(); }
	int newnode(){ x[size].init(); return size++; }
	void add(int c,int t){
		int p=newnode(),tmp=last;
		x[p].len=x[last].len+1;
		for (;~tmp&&!~x[tmp].next[c];tmp=x[tmp].fail) x[tmp].next[c]=p;
		if (!~tmp) x[p].fail=0;
		else {
			int q=x[tmp].next[c];
			if (x[tmp].len+1==x[q].len) x[p].fail=q;
			else {
				int np=newnode();
				x[np]=x[q]; x[np].len=x[tmp].len+1; x[p].fail=x[q].fail=np;
				for (;~tmp&&x[tmp].next[c]==q;tmp=x[tmp].fail) x[tmp].next[c]=np;
				type[np]=0;
			}
		}
		last=p;
		type[p]=t;
	}
	void walk(char s[]){
		int n=strlen(s+1),now=0;
		FOR(i,1,n) {
			for (;~now&&!~x[now].next[s[i]-'a'];now=x[now].fail);
			if (!~now) now=0; else now=x[now].next[s[i]-'a'];
			pos[i]=now;
			//printf("%d%c",pos[i]," \n"[i==n]);
		}
	}
	void print(){
		FOR(i,0,size-1) {
			printf("node[%d]: len=%d fail=%d\n",i,x[i].len,x[i].fail);
			FOR(j,0,2) printf("%c-%d%c",'a'+j,x[i].next[j]," \n"[j==2]);
		}
	}
};
char s[MAXN],t[MAXN];
int n,m,q,fa[MAXN][15];
int u[MAXM<<1],esize;
struct edge{ int v,nt; }e[MAXM<<1];
void clear(){ memset(u,-1,sizeof(u)); esize=0; }
void addEdge(int i,int j){
	//printf("%d %d\n",i,j);
	e[esize]=(edge){j,u[i]}; u[i]=esize++;
}
void dfs1(int x,int y){
	fa[x][0]=y;
	FOR(i,1,14) fa[x][i]=fa[fa[x][i-1]][i-1];
	for (int i=u[x];~i;i=e[i].nt) {
		int v=e[i].v;
		dfs1(v,x);
	}
}
pair<int,int> ans[MAXN];
struct Data{ int l,r,i; };
vector <Data> Q[MAXM<<1];
int rt[MAXM<<1],treesize;
struct treenode{ int l,r,max,x; }tr[400005];
void treeins(int &x,int l,int r,int k){
	if (x==0) {
		x=++treesize;
		tr[x].l=tr[x].r=tr[x].max=0;
	}
	if (l==r) {
		tr[x].max++,tr[x].x=l;
		return;
	}
	int mid=(l+r)/2;
	if (k<=mid) treeins(tr[x].l,l,mid,k);
	else treeins(tr[x].r,mid+1,r,k);
	if (tr[tr[x].l].max>=tr[tr[x].r].max) tr[x].max=tr[tr[x].l].max,tr[x].x=tr[tr[x].l].x;
	else tr[x].max=tr[tr[x].r].max,tr[x].x=tr[tr[x].r].x;
}
void treemerge(int &x,int y,int l,int r){
	if (!x||!y) { x=x+y; return; }
	if (l==r) {
		tr[x].max+=tr[y].max;
		return;
	}
	int mid=(l+r)/2;
	treemerge(tr[x].l,tr[y].l,l,mid);
	treemerge(tr[x].r,tr[y].r,mid+1,r);
	if (tr[tr[x].l].max>=tr[tr[x].r].max) tr[x].max=tr[tr[x].l].max,tr[x].x=tr[tr[x].l].x;
	else tr[x].max=tr[tr[x].r].max,tr[x].x=tr[tr[x].r].x;
}
pair<int,int> treequery(int x,int l,int r,int L,int R){
	if (!x) return make_pair(0,L);
	if (L<=l&&r<=R) return make_pair(tr[x].max,tr[x].x);
	int mid=(l+r)/2;
	pair<int,int> ans1,ans2; ans1=ans2=make_pair(0,L);
	if (L<=mid) ans1=treequery(tr[x].l,l,mid,L,R);
	if (mid<R) ans2=treequery(tr[x].r,mid+1,r,L,R);
	if (ans1.first>=ans2.first) return ans1;
	return ans2;
}
void treeprint(int x,int l,int r){
	if (!x) return;
	printf("(%d,%d,%d,[%d %d])",x,tr[x].max,tr[x].x,l,r);
	if (l==r) return;
	putchar('{');
	int mid=(l+r)/2;
	treeprint(tr[x].l,l,mid);
	treeprint(tr[x].r,mid+1,r);
	putchar('}');
}
void dfs2(int x){
	rt[x]=0;
	//printf("%d type=%d\n",x,SAM::type[x]);
	if (SAM::type[x]) treeins(rt[x],1,m,SAM::type[x]);
	//treeprint(rt[x],1,m); puts("");
	for (int i=u[x];~i;i=e[i].nt) {
		int v=e[i].v;
		dfs2(v);
		treemerge(rt[x],rt[v],1,m);
		//treeprint(rt[x],1,m); puts("");
	}
	for (int i=0;i<(int)Q[x].size();++i) ans[Q[x][i].i]=treequery(rt[x],1,m,Q[x][i].l,Q[x][i].r);
}
int main(){
	scanf("%s",s+1); n=strlen(s+1);
	SAM::init();
	m=read();
	FOR(i,1,m) {
		scanf("%s",t+1); q=strlen(t+1);
		SAM::last=0;
		FOR(j,1,q) SAM::add(t[j]-'a',i);
	}
	clear();
	FOR(i,1,SAM::size-1) addEdge(SAM::x[i].fail,i);
	dfs1(0,0);
	SAM::walk(s);
	//SAM::print();
	q=read();
	FOR(i,1,q) {
		int l=read(),r=read(),pl=read(),pr=read();
		int now=SAM::pos[pr];
		ROF(k,14,0)
		if (SAM::x[fa[now][k]].len>=pr-pl+1) now=fa[now][k];
		//printf("now=%d nowlen=%d\n",now,SAM::x[now].len);
		if (now&&SAM::x[now].len>=pr-pl+1) Q[now].push_back((Data){l,r,i});
		else ans[i]=make_pair(0,l);
	}
	treesize=0; dfs2(0);
	FOR(i,1,q) printf("%d %d\n",ans[i].second,ans[i].first);

	return 0;
}

/*
suffixtree
3
suffixtreesareawesome
cartesiantreeisworsethansegmenttree
nyeeheeheee
2
1 2 1 10
1 3 9 10

cbcbbaba
6
aba
a
bbcba
b
abc
ac
1
3 5 1 7

*/


#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for (int i=(a);i<=(b);++i)
#define ROF(i,a,b) for (int i=(a);i>=(b);--i)
typedef long long ll;
inline int read(){
	int x=0,f=1; char ch=getchar();
	while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
	while (isdigit(ch)) { x=x*10+ch-'0'; ch=getchar(); }
	return x*f;
}

const int MAXN=500005,MAXM=50004;
namespace SAM{
	struct Node{
		int next[26],fail,len;
		void init(){ fail=-1; len=0; memset(next,-1,sizeof(next)); }
	}x[MAXM<<1];
	int size,last,type[MAXM<<1],pos[MAXN];
	void init(){ size=last=0; x[size++].init(); }
	int newnode(){ x[size].init(); return size++; }
	void add(int c,int t){
		int p=newnode(),tmp=last;
		x[p].len=x[last].len+1;
		for (;~tmp&&!~x[tmp].next[c];tmp=x[tmp].fail) x[tmp].next[c]=p;
		if (!~tmp) x[p].fail=0;
		else {
			int q=x[tmp].next[c];
			if (x[tmp].len+1==x[q].len) x[p].fail=q;
			else {
				int np=newnode();
				x[np]=x[q]; x[np].len=x[tmp].len+1; x[p].fail=x[q].fail=np;
				for (;~tmp&&x[tmp].next[c]==q;tmp=x[tmp].fail) x[tmp].next[c]=np;
				type[np]=0;
			}
		}
		last=p;
		type[p]=t;
	}
	void walk(char s[]){
		int n=strlen(s+1),now=0;
		FOR(i,1,n) {
			for (;~now&&!~x[now].next[s[i]-'a'];now=x[now].fail);
			if (!~now) now=0; else now=x[now].next[s[i]-'a'];
			pos[i]=now;
			//printf("%d%c",pos[i]," \n"[i==n]);
		}
	}
	void print(){
		FOR(i,0,size-1) {
			printf("node[%d]: len=%d fail=%d\n",i,x[i].len,x[i].fail);
			FOR(j,0,2) printf("%c-%d%c",'a'+j,x[i].next[j]," \n"[j==2]);
		}
	}
};
char s[MAXN],t[MAXN];
int n,m,q,fa[MAXN][15];
int u[MAXM<<1],esize;
struct edge{ int v,nt; }e[MAXM<<1];
void clear(){ memset(u,-1,sizeof(u)); esize=0; }
void addEdge(int i,int j){
	//printf("%d %d\n",i,j);
	e[esize]=(edge){j,u[i]}; u[i]=esize++;
}
void dfs1(int x,int y){
	fa[x][0]=y;
	FOR(i,1,14) fa[x][i]=fa[fa[x][i-1]][i-1];
	for (int i=u[x];~i;i=e[i].nt) {
		int v=e[i].v;
		dfs1(v,x);
	}
}
pair<int,int> ans[MAXN];
struct Data{ int l,r,i; };
vector <Data> Q[MAXM<<1];
int rt[MAXM<<1],treesize;
struct treenode{ int l,r,max,x; }tr[400005];
void treeins(int &x,int l,int r,int k){
	if (x==0) {
		x=++treesize;
		tr[x].l=tr[x].r=tr[x].max=0;
	}
	if (l==r) {
		tr[x].max++,tr[x].x=l;
		return;
	}
	int mid=(l+r)/2;
	if (k<=mid) treeins(tr[x].l,l,mid,k);
	else treeins(tr[x].r,mid+1,r,k);
	if (tr[tr[x].l].max>=tr[tr[x].r].max) tr[x].max=tr[tr[x].l].max,tr[x].x=tr[tr[x].l].x;
	else tr[x].max=tr[tr[x].r].max,tr[x].x=tr[tr[x].r].x;
}
void treemerge(int &x,int y,int l,int r){
	if (!x||!y) { x=x+y; return; }
	if (l==r) {
		tr[x].max+=tr[y].max;
		return;
	}
	int mid=(l+r)/2;
	treemerge(tr[x].l,tr[y].l,l,mid);
	treemerge(tr[x].r,tr[y].r,mid+1,r);
	if (tr[tr[x].l].max>=tr[tr[x].r].max) tr[x].max=tr[tr[x].l].max,tr[x].x=tr[tr[x].l].x;
	else tr[x].max=tr[tr[x].r].max,tr[x].x=tr[tr[x].r].x;
}
pair<int,int> treequery(int x,int l,int r,int L,int R){
	if (!x) return make_pair(0,L);
	if (L<=l&&r<=R) return make_pair(tr[x].max,tr[x].x);
	int mid=(l+r)/2;
	pair<int,int> ans1,ans2; ans1=ans2=make_pair(0,L);
	if (L<=mid) ans1=treequery(tr[x].l,l,mid,L,R);
	if (mid<R) ans2=treequery(tr[x].r,mid+1,r,L,R);
	if (ans1.first>=ans2.first) return ans1;
	return ans2;
}
void treeprint(int x,int l,int r){
	if (!x) return;
	printf("(%d,%d,%d,[%d %d])",x,tr[x].max,tr[x].x,l,r);
	if (l==r) return;
	putchar('{');
	int mid=(l+r)/2;
	treeprint(tr[x].l,l,mid);
	treeprint(tr[x].r,mid+1,r);
	putchar('}');
}
void dfs2(int x){
	rt[x]=0;
	//printf("%d type=%d\n",x,SAM::type[x]);
	if (SAM::type[x]) treeins(rt[x],1,m,SAM::type[x]);
	//treeprint(rt[x],1,m); puts("");
	for (int i=u[x];~i;i=e[i].nt) {
		int v=e[i].v;
		dfs2(v);
		treemerge(rt[x],rt[v],1,m);
		//treeprint(rt[x],1,m); puts("");
	}
	for (int i=0;i<(int)Q[x].size();++i) ans[Q[x][i].i]=treequery(rt[x],1,m,Q[x][i].l,Q[x][i].r);
}
int main(){
	scanf("%s",s+1); n=strlen(s+1);
	SAM::init();
	m=read();
	FOR(i,1,m) {
		scanf("%s",t+1); q=strlen(t+1);
		SAM::last=0;
		FOR(j,1,q) SAM::add(t[j]-'a',i);
	}
	clear();
	FOR(i,1,SAM::size-1) addEdge(SAM::x[i].fail,i);
	dfs1(0,0);
	SAM::walk(s);
	//SAM::print();
	q=read();
	FOR(i,1,q) {
		int l=read(),r=read(),pl=read(),pr=read();
		int now=SAM::pos[pr];
		ROF(k,14,0)
		if (SAM::x[fa[now][k]].len>=pr-pl+1) now=fa[now][k];
		//printf("now=%d nowlen=%d\n",now,SAM::x[now].len);
		if (now) Q[now].push_back((Data){l,r,i});
	}
	treesize=0; dfs2(0);
	FOR(i,1,q) printf("%d %d\n",ans[i].second,ans[i].first);

	return 0;
}

/*
suffixtree
3
suffixtreesareawesome
cartesiantreeisworsethansegmenttree
nyeeheeheee
2
1 2 1 10
1 3 9 10

ab
3
abc
aab
bbb
2
1 2 1 2
1 3 2 2

*/


#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for (int i=(a);i<=(b);++i)
#define ROF(i,a,b) for (int i=(a);i>=(b);--i)
typedef long long ll;
inline int read(){
	int x=0,f=1; char ch=getchar();
	while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
	while (isdigit(ch)) { x=x*10+ch-'0'; ch=getchar(); }
	return x*f;
}

const int MAXN=500005,MAXM=50004;
namespace SAM{
	struct Node{
		int next[26],fail,len;
		void init(){ fail=-1; len=0; memset(next,-1,sizeof(next)); }
	}x[MAXM<<1];
	int size,last,type[MAXM<<1],pos[MAXN],lcs[MAXN];
	void init(){ size=last=0; x[size++].init(); }
	int newnode(){ x[size].init(); return size++; }
	void add(int c,int t){
		int p=newnode(),tmp=last;
		x[p].len=x[last].len+1;
		for (;~tmp&&!~x[tmp].next[c];tmp=x[tmp].fail) x[tmp].next[c]=p;
		if (!~tmp) x[p].fail=0;
		else {
			int q=x[tmp].next[c];
			if (x[tmp].len+1==x[q].len) x[p].fail=q;
			else {
				int np=newnode();
				x[np]=x[q]; x[np].len=x[tmp].len+1; x[p].fail=x[q].fail=np;
				for (;~tmp&&x[tmp].next[c]==q;tmp=x[tmp].fail) x[tmp].next[c]=np;
				type[np]=0;
			}
		}
		last=p;
		type[p]=t;
	}
	void walk(char s[]){
		int n=strlen(s+1),now=0,len=0;
		FOR(i,1,n) {
			for (;~now&&!~x[now].next[s[i]-'a'];now=x[now].fail);
			if (!~now) now=len=0;
			else len=min(len,x[now].len)+1,now=x[now].next[s[i]-'a'];
			pos[i]=now; lcs[i]=len;
			//printf("(%d,%d)%c",pos[i],lcs[i]," \n"[i==n]);
		}
	}
	void print(){
		FOR(i,0,size-1) {
			printf("node[%d]: len=%d fail=%d\n",i,x[i].len,x[i].fail);
			FOR(j,0,2) printf("%c%d%c",'a'+j,x[i].next[j]," \n"[j==2]);
		}
	}
};
char s[MAXN],t[MAXN];
int n,m,q,fa[MAXN][15];
int u[MAXM<<1],esize;
struct edge{ int v,nt; }e[MAXM<<1];
void clear(){ memset(u,-1,sizeof(u)); esize=0; }
void addEdge(int i,int j){
	//printf("%d %d\n",i,j);
	e[esize]=(edge){j,u[i]}; u[i]=esize++;
}
void dfs1(int x,int y){
	fa[x][0]=y;
	FOR(i,1,14) fa[x][i]=fa[fa[x][i-1]][i-1];
	for (int i=u[x];~i;i=e[i].nt) {
		int v=e[i].v;
		dfs1(v,x);
	}
}
pair<int,int> ans[MAXN];
struct Data{ int l,r,i; };
vector <Data> Q[MAXM<<1];
int rt[MAXM<<1],treesize;
struct treenode{ int l,r,max,x; }tr[400005];
void treeins(int &x,int l,int r,int k){
	if (x==0) {
		x=++treesize;
		tr[x].l=tr[x].r=tr[x].max=0;
	}
	if (l==r) {
		tr[x].max++,tr[x].x=l;
		return;
	}
	int mid=(l+r)/2;
	if (k<=mid) treeins(tr[x].l,l,mid,k);
	else treeins(tr[x].r,mid+1,r,k);
	if (tr[tr[x].l].max>=tr[tr[x].r].max) tr[x].max=tr[tr[x].l].max,tr[x].x=tr[tr[x].l].x;
	else tr[x].max=tr[tr[x].r].max,tr[x].x=tr[tr[x].r].x;
}
void treemerge(int &x,int y,int l,int r){
	if (!x||!y) { x=x+y; return; }
	if (l==r) {
		tr[x].max+=tr[y].max;
		return;
	}
	int mid=(l+r)/2;
	treemerge(tr[x].l,tr[y].l,l,mid);
	treemerge(tr[x].r,tr[y].r,mid+1,r);
	if (tr[tr[x].l].max>=tr[tr[x].r].max) tr[x].max=tr[tr[x].l].max,tr[x].x=tr[tr[x].l].x;
	else tr[x].max=tr[tr[x].r].max,tr[x].x=tr[tr[x].r].x;
}
pair<int,int> treequery(int x,int l,int r,int L,int R){
	if (!x) return make_pair(0,L);
	if (L<=l&&r<=R) return make_pair(tr[x].max,tr[x].x);
	int mid=(l+r)/2;
	pair<int,int> ans1,ans2; ans1=ans2=make_pair(0,L);
	if (L<=mid) ans1=treequery(tr[x].l,l,mid,L,R);
	if (mid<R) ans2=treequery(tr[x].r,mid+1,r,L,R);
	if (ans1.first>=ans2.first) return ans1;
	return ans2;
}
void treeprint(int x,int l,int r){
	if (!x) return;
	printf("(%d,%d,%d,[%d %d])",x,tr[x].max,tr[x].x,l,r);
	if (l==r) return;
	putchar('{');
	int mid=(l+r)/2;
	treeprint(tr[x].l,l,mid);
	treeprint(tr[x].r,mid+1,r);
	putchar('}');
}
void dfs2(int x){
	rt[x]=0;
	//printf("%d type=%d\n",x,SAM::type[x]);
	if (SAM::type[x]) treeins(rt[x],1,m,SAM::type[x]);
	//treeprint(rt[x],1,m); puts("");
	for (int i=u[x];~i;i=e[i].nt) {
		int v=e[i].v;
		dfs2(v);
		treemerge(rt[x],rt[v],1,m);
		//treeprint(rt[x],1,m); puts("");
	}
	for (int i=0;i<(int)Q[x].size();++i) ans[Q[x][i].i]=treequery(rt[x],1,m,Q[x][i].l,Q[x][i].r);
}
int main(){
	scanf("%s",s+1); n=strlen(s+1);
	SAM::init();
	m=read();
	FOR(i,1,m) {
		scanf("%s",t+1); q=strlen(t+1);
		SAM::last=0;
		FOR(j,1,q) SAM::add(t[j]-'a',i);
	}
	clear();
	FOR(i,1,SAM::size-1) addEdge(SAM::x[i].fail,i);
	dfs1(0,0);
	SAM::walk(s);
	//SAM::print();
	q=read();
	FOR(i,1,q) {
		int l=read(),r=read(),pl=read(),pr=read();
		if (pr-pl+1>SAM::lcs[pr]) { ans[i]=make_pair(0,l); continue; }
		int now=SAM::pos[pr];
		ROF(k,14,0)
		if (SAM::x[fa[now][k]].len>=pr-pl+1) now=fa[now][k];
		//printf("i=%d now=%d nowlen=%d\n",i,now,SAM::x[now].len);
		if (now&&SAM::x[now].len>=pr-pl+1) Q[now].push_back((Data){l,r,i});
		else ans[i]=make_pair(0,l);
	}
	treesize=0; dfs2(0);
	FOR(i,1,q) printf("%d %d\n",ans[i].second,ans[i].first);

	return 0;
}

/*
suffixtree
3
suffixtreesareawesome
cartesiantreeisworsethansegmenttree
nyeeheeheee
2
1 2 1 10
1 3 9 10

cbcbbaba
6
aba
a
bbcba
b
abc
ac
1
3 5 1 7

caccc
4
bbb
abb
bccac
baacc
1
3 4 1 4

*/


#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for (int i=(a);i<=(b);++i)
#define ROF(i,a,b) for (int i=(a);i>=(b);--i)
typedef long long ll;
inline int read(){
	int x=0,f=1; char ch=getchar();
	while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
	while (isdigit(ch)) { x=x*10+ch-'0'; ch=getchar(); }
	return x*f;
}

const int MAXN=500005,MAXM=50004;
namespace SAM{
	struct Node{
		int next[26],fail,len;
		void init(){ fail=-1; len=0; memset(next,-1,sizeof(next)); }
	}x[MAXM<<1];
	int size,last,type[MAXM<<1],pos[MAXN];
	void init(){ size=last=0; x[size++].init(); }
	int newnode(){ x[size].init(); return size++; }
	void add(int c,int t){
		int p=newnode(),tmp=last;
		x[p].len=x[last].len+1;
		for (;~tmp&&!~x[tmp].next[c];tmp=x[tmp].fail) x[tmp].next[c]=p;
		if (!~tmp) x[p].fail=0;
		else {
			int q=x[tmp].next[c];
			if (x[tmp].len+1==x[q].len) x[p].fail=q;
			else {
				int np=newnode();
				x[np]=x[q]; x[np].len=x[tmp].len+1; x[p].fail=x[q].fail=np;
				for (;~tmp&&x[tmp].next[c]==q;tmp=x[tmp].fail) x[tmp].next[c]=np;
				type[np]=0;
			}
		}
		last=p;
		type[p]=t;
	}
	void walk(char s[]){
		int n=strlen(s+1),now=0;
		FOR(i,1,n) {
			for (;~now&&!~x[now].next[s[i]-'a'];now=x[now].fail);
			if (!~now) now=0; else now=x[now].next[s[i]-'a'];
			pos[i]=now;
			//printf("%d%c",pos[i]," \n"[i==n]);
		}
	}
	void print(){
		FOR(i,0,size-1) {
			printf("node[%d]: len=%d fail=%d\n",i,x[i].len,x[i].fail);
			FOR(j,0,2) printf("%c-%d%c",'a'+j,x[i].next[j]," \n"[j==2]);
		}
	}
};
char s[MAXN],t[MAXN];
int n,m,q,fa[MAXN][15];
int u[MAXM<<1],esize;
struct edge{ int v,nt; }e[MAXM<<1];
void clear(){ memset(u,-1,sizeof(u)); esize=0; }
void addEdge(int i,int j){
	//printf("%d %d\n",i,j);
	e[esize]=(edge){j,u[i]}; u[i]=esize++;
}
void dfs1(int x,int y){
	fa[x][0]=y;
	FOR(i,1,14) fa[x][i]=fa[fa[x][i-1]][i-1];
	for (int i=u[x];~i;i=e[i].nt) {
		int v=e[i].v;
		dfs1(v,x);
	}
}
pair<int,int> ans[MAXN];
struct Data{ int l,r,i; };
vector <Data> Q[MAXM<<1];
int rt[MAXM<<1],treesize;
struct treenode{ int l,r,max,x; }tr[400005];
void treeins(int &x,int l,int r,int k){
	if (x==0) {
		x=++treesize;
		tr[x].l=tr[x].r=tr[x].max=0;
	}
	if (l==r) {
		tr[x].max++,tr[x].x=l;
		return;
	}
	int mid=(l+r)/2;
	if (k<=mid) treeins(tr[x].l,l,mid,k);
	else treeins(tr[x].r,mid+1,r,k);
	if (tr[tr[x].l].max>=tr[tr[x].r].max) tr[x].max=tr[tr[x].l].max,tr[x].x=tr[tr[x].l].x;
	else tr[x].max=tr[tr[x].r].max,tr[x].x=tr[tr[x].r].x;
}
void treemerge(int &x,int y,int l,int r){
	if (!x||!y) { x=x+y; return; }
	if (l==r) {
		tr[x].max+=tr[y].max;
		return;
	}
	int mid=(l+r)/2;
	treemerge(tr[x].l,tr[y].l,l,mid);
	treemerge(tr[x].r,tr[y].r,mid+1,r);
	if (tr[tr[x].l].max>=tr[tr[x].r].max) tr[x].max=tr[tr[x].l].max,tr[x].x=tr[tr[x].l].x;
	else tr[x].max=tr[tr[x].r].max,tr[x].x=tr[tr[x].r].x;
}
pair<int,int> treequery(int x,int l,int r,int L,int R){
	if (!x) return make_pair(0,L);
	if (L<=l&&r<=R) return make_pair(tr[x].max,tr[x].x);
	int mid=(l+r)/2;
	pair<int,int> ans1,ans2; ans1=ans2=make_pair(0,L);
	if (L<=mid) ans1=treequery(tr[x].l,l,mid,L,R);
	if (mid<R) ans2=treequery(tr[x].r,mid+1,r,L,R);
	if (ans1.first>=ans2.first) return ans1;
	return ans2;
}
void treeprint(int x,int l,int r){
	if (!x) return;
	printf("(%d,%d,%d,[%d %d])",x,tr[x].max,tr[x].x,l,r);
	if (l==r) return;
	putchar('{');
	int mid=(l+r)/2;
	treeprint(tr[x].l,l,mid);
	treeprint(tr[x].r,mid+1,r);
	putchar('}');
}
void dfs2(int x){
	rt[x]=0;
	//printf("%d type=%d\n",x,SAM::type[x]);
	if (SAM::type[x]) treeins(rt[x],1,m,SAM::type[x]);
	//treeprint(rt[x],1,m); puts("");
	for (int i=u[x];~i;i=e[i].nt) {
		int v=e[i].v;
		dfs2(v);
		treemerge(rt[x],rt[v],1,m);
		//treeprint(rt[x],1,m); puts("");
	}
	for (int i=0;i<(int)Q[x].size();++i) ans[Q[x][i].i]=treequery(rt[x],1,m,Q[x][i].l,Q[x][i].r);
}
int main(){
	scanf("%s",s+1); n=strlen(s+1);
	SAM::init();
	m=read();
	FOR(i,1,m) {
		scanf("%s",t+1); q=strlen(t+1);
		SAM::last=0;
		FOR(j,1,q) SAM::add(t[j]-'a',i);
	}
	clear();
	FOR(i,1,SAM::size-1) addEdge(SAM::x[i].fail,i);
	dfs1(0,0);
	SAM::walk(s);
	//SAM::print();
	q=read();
	FOR(i,1,q) {
		int l=read(),r=read(),pl=read(),pr=read();
		int now=SAM::pos[pr];
		ROF(k,14,0)
		if (SAM::x[fa[now][k]].len>=pr-pl+1) now=fa[now][k];
		//printf("now=%d nowlen=%d\n",now,SAM::x[now].len);
		Q[now].push_back((Data){l,r,i});
	}
	treesize=0; dfs2(0);
	FOR(i,1,q) printf("%d %d\n",ans[i].second,ans[i].first);

	return 0;
}

/*
suffixtree
3
suffixtreesareawesome
cartesiantreeisworsethansegmenttree
nyeeheeheee
2
1 2 1 10
1 3 9 10

ab
3
abc
aab
bbb
2
1 2 1 2
1 3 2 2

*/


#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for (int i=(a);i<=(b);++i)
#define ROF(i,a,b) for (int i=(a);i>=(b);--i)
typedef long long ll;
inline int read(){
	int x=0,f=1; char ch=getchar();
	while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
	while (isdigit(ch)) { x=x*10+ch-'0'; ch=getchar(); }
	return x*f;
}

const int MAXN=500005,MAXM=50004;
namespace SAM{
	struct Node{
		int next[26],fail,len;
		void init(){ fail=-1; len=0; memset(next,-1,sizeof(next)); }
	}x[MAXM<<1];
	int size,last,type[MAXM<<1],pos[MAXN];
	void init(){ size=last=0; x[size++].init(); }
	int newnode(){ x[size].init(); return size++; }
	void add(int c,int t){
		int p=newnode(),tmp=last;
		x[p].len=x[last].len+1;
		for (;~tmp&&!~x[tmp].next[c];tmp=x[tmp].fail) x[tmp].next[c]=p;
		if (!~tmp) x[p].fail=0;
		else {
			int q=x[tmp].next[c];
			if (x[tmp].len+1==x[q].len) x[p].fail=q;
			else {
				int np=newnode();
				x[np]=x[q]; x[np].len=x[tmp].len+1; x[p].fail=x[q].fail=np;
				for (;~tmp&&x[tmp].next[c]==q;tmp=x[tmp].fail) x[tmp].next[c]=np;
				type[np]=0;
			}
		}
		last=p;
		type[p]=t;
	}
	void walk(char s[]){
		int n=strlen(s+1),now=0;
		FOR(i,1,n) {
			for (;~now&&!~x[now].next[s[i]-'a'];now=x[now].fail);
			if (!~now) now=0; else now=x[now].next[s[i]-'a'];
			pos[i]=now;
			//printf("%d%c",pos[i]," \n"[i==n]);
		}
	}
	void print(){
		FOR(i,0,size-1) {
			printf("node[%d]: len=%d fail=%d\n",i,x[i].len,x[i].fail);
			FOR(j,0,2) printf("%c-%d%c",'a'+j,x[i].next[j]," \n"[j==2]);
		}
	}
};
char s[MAXN],t[MAXN];
int n,m,q,fa[MAXN][15];
struct data{ int l,r,i; };
int u[MAXM<<1],esize;
struct edge{ int v,nt; }e[MAXM<<1];
void clear(){ memset(u,-1,sizeof(u)); esize=0; }
void addEdge(int i,int j){
	//printf("%d %d\n",i,j);
	e[esize]=(edge){j,u[i]}; u[i]=esize++;
}
void dfs1(int x,int y){
	fa[x][0]=y;
	FOR(i,1,14) fa[x][i]=fa[fa[x][i-1]][i-1];
	for (int i=u[x];~i;i=e[i].nt) {
		int v=e[i].v;
		dfs1(v,x);
	}
}
pair<int,int> ans[MAXN];
vector<data> Q[MAXM<<1];
int rt[MAXM<<1],treesize;
struct treenode{ int l,r,max,x; }tr[400005];
void treeins(int &x,int l,int r,int k){
	if (x==0) {
		x=++treesize;
		tr[x].l=tr[x].r=tr[x].max=0;
	}
	if (l==r) {
		tr[x].max++,tr[x].x=l;
		return;
	}
	int mid=(l+r)/2;
	if (k<=mid) treeins(tr[x].l,l,mid,k);
	else treeins(tr[x].r,mid+1,r,k);
	if (tr[tr[x].l].max>=tr[tr[x].r].max) tr[x].max=tr[tr[x].l].max,tr[x].x=tr[tr[x].l].x;
	else tr[x].max=tr[tr[x].r].max,tr[x].x=tr[tr[x].r].x;
}
void treemerge(int &x,int y,int l,int r){
	if (!x||!y) { x=x+y; return; }
	if (l==r) {
		tr[x].max+=tr[y].max;
		return;
	}
	int mid=(l+r)/2;
	treemerge(tr[x].l,tr[y].l,l,mid);
	treemerge(tr[x].r,tr[y].r,mid+1,r);
	if (tr[tr[x].l].max>=tr[tr[x].r].max) tr[x].max=tr[tr[x].l].max,tr[x].x=tr[tr[x].l].x;
	else tr[x].max=tr[tr[x].r].max,tr[x].x=tr[tr[x].r].x;
}
pair<int,int> ans0=make_pair(0,0);
pair<int,int> treequery(int x,int l,int r,int L,int R){
	if (!x) return ans0;
	if (L<=l&&r<=R) return make_pair(tr[x].max,tr[x].x);
	int mid=(l+r)/2;
	pair<int,int> ans1=ans0,ans2=ans0;
	if (L<=mid) ans1=treequery(tr[x].l,l,mid,L,R);
	if (mid<R) ans2=treequery(tr[x].r,mid+1,r,L,R);
	if (ans1.first>=ans2.first) return ans1;
	return ans2;
}
void treeprint(int x,int l,int r){
	if (!x) return;
	printf("(%d,%d,%d,[%d %d])",x,tr[x].max,tr[x].x,l,r);
	if (l==r) return;
	putchar('{');
	int mid=(l+r)/2;
	treeprint(tr[x].l,l,mid);
	treeprint(tr[x].r,mid+1,r);
	putchar('}');
}
void dfs2(int x){
	rt[x]=0;
	//printf("%d type=%d\n",x,SAM::type[x]);
	if (SAM::type[x]) treeins(rt[x],1,m,SAM::type[x]);
	//treeprint(rt[x],1,m); puts("");
	for (int i=u[x];~i;i=e[i].nt) {
		int v=e[i].v;
		dfs2(v);
		treemerge(rt[x],rt[v],1,m);
		//treeprint(rt[x],1,m); puts("");
	}
	for (int i=0;i<(int)Q[x].size();++i) ans[Q[x][i].i]=treequery(rt[x],1,m,Q[x][i].l,Q[x][i].r);
}
int main(){
	scanf("%s",s+1); n=strlen(s+1);
	SAM::init();
	m=read();
	FOR(i,1,m) {
		scanf("%s",t+1); q=strlen(t+1);
		SAM::last=0;
		FOR(j,1,q) SAM::add(t[j]-'a',i);
	}
	clear();
	FOR(i,1,SAM::size-1) addEdge(SAM::x[i].fail,i);
	dfs1(0,0);
	SAM::walk(s);
	//SAM::print();
	q=read();
	FOR(i,1,q) {
		int l=read(),r=read(),pl=read(),pr=read();
		int now=SAM::pos[pr];
		ROF(k,14,0)
		if (SAM::x[fa[now][k]].len>=pr-pl+1) now=fa[now][k];
		//printf("now=%d nowlen=%d\n",now,SAM::x[now].len);
		Q[now].push_back((data){l,r,i});
	}
	treesize=0; dfs2(0);
	FOR(i,1,q) printf("%d %d\n",ans[i].second,ans[i].first);

	return 0;
}

/*
suffixtree
3
suffixtreesareawesome
cartesiantreeisworsethansegmenttree
nyeeheeheee
2
1 2 1 10
1 3 9 10

ab
3
abc
aab
bbb
2
1 2 1 2
1 3 2 2

*/


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=500005;
const int MXN=1200005;
const int P=20;
int n,m,ch[MXN][27],pa[MXN],len[MXN],anc[MXN][P+3],root=1,last=1,pos[N],tail=1;
int Root[MXN],Tail=0,q,tx[MXN];
bool cmp(const int &A,const int &B){return len[A]<len[B];}
char s[N];
struct data
{
	int x,y;
	data(){}
	data(int x,int y):x(x),y(y){}
	data operator+(const data &B)
	{
		if(x==B.x) return data(x,y+B.y);
		if(y>B.y||(y==B.y&&x<B.x)) return data(x,y);
		else return data(B.x,B.y);
	}
	void pt(int ss){cout<<ss<<" : "<<x<<" "<<y<<endl;}
};
struct node
{
	int ls,rs;
	data p;
}tr[MXN*30];
void insert(int c)
{
	int nd=++tail; len[tail]=len[last]+1; int tmp=last;
	while(tmp&&!ch[tmp][c]) ch[tmp][c]=nd,tmp=pa[tmp];
	if(tmp==0) pa[nd]=root;
	else
	{
		int B=ch[tmp][c];
		if(len[B]==len[tmp]+1) pa[nd]=B;
		else
		{
			int nB=++tail; len[nB]=len[tmp]+1;
			for(int i=0;i<=26;i++) ch[nB][i]=ch[B][i];
			while(tmp&&ch[tmp][c]==B) ch[tmp][c]=nB,tmp=pa[tmp];
			pa[nB]=pa[B]; pa[B]=nB; pa[nd]=nB;
		}
	}
	last=nd;
}
void insert(int &nd,int lf,int rg,int pos)
{
	if(!nd) nd=++Tail,tr[nd].p=data(0,0);
	if(lf==rg)
	{
		if(!tr[nd].p.y) tr[nd].p=data(pos,1);
		else tr[nd].p.y++;
		return;
	}
	int mid=(lf+rg)>>1;
	if(pos<=mid) insert(tr[nd].ls,lf,mid,pos);
	else insert(tr[nd].rs,mid+1,rg,pos);
	tr[nd].p=tr[tr[nd].ls].p+tr[tr[nd].rs].p;
}
int merge(int x,int y,int lf,int rg)
{
	if(!x||!y) return x|y;
	int z=++Tail;
	if(lf==rg)
	{
		tr[z].p=tr[x].p+tr[y].p;
		return z;
	}
	int mid=(lf+rg)>>1;
	tr[z].ls=merge(tr[x].ls,tr[y].ls,lf,mid);
	tr[z].rs=merge(tr[x].rs,tr[y].rs,mid+1,rg);
	tr[z].p=tr[tr[z].ls].p+tr[tr[z].rs].p;
	return z;
}
void init()
{
	for(int i=1;i<=tail;i++) tx[i]=i;
	sort(tx+1,tx+tail+1,cmp);
	for(int j=tail;j>=1;j--)
	{
		int i=tx[j];
		if(pa[i]) Root[pa[i]]=merge(Root[pa[i]],Root[i],1,m);

	}
	for(int j=1;j<=tail;j++)
	{
		int i=tx[j];
		anc[i][0]=pa[i];
		for(int p=1;p<=P;p++) anc[i][p]=anc[anc[i][p-1]][p-1];
	}
}
data query(int nd,int lf,int rg,int L,int R)
{
	if(L<=lf&&rg<=R) return tr[nd].p;
	int mid=(lf+rg)>>1;
	data ret=data(0,0);
	if(L<=mid) ret=ret+query(tr[nd].ls,lf,mid,L,R);
	if(R>mid) ret=ret+query(tr[nd].rs,mid+1,rg,L,R);
	return ret;
}
int main()
{
//	freopen("out.out","w",stdout);
	scanf("%s",s+1); n=strlen(s+1);
	for(int i=1;i<=n;i++) insert(s[i]-'a'),pos[i]=last; insert(26);
	scanf("%d",&m);
	for(int j=1;j<=m;j++)
	{
		scanf("%s",s); int l=strlen(s);
		for(int i=0;i<l;i++)
		insert(s[i]-'a'),insert(Root[last],1,m,j);
		insert(26);
	}
	init();
	scanf("%d",&q);
	while(q--)
	{
		int l,r,L,R; scanf("%d%d%d%d",&l,&r,&L,&R);
		int x=pos[R];
		for(int i=P;i>=0;i--) if(len[anc[x][i]]>=R-L+1) x=anc[x][i];
	//	printf("x=%d len=%d\n",x,len[x]);
		data u=query(Root[x],1,m,l,r);
		if(!u.y) printf("%d %d\n",1,0);
		else printf("%d %d\n",u.x,u.y);
	}
	return 0;
}


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=500005;
const int MXN=1200005;
const int P=20;
int n,m,ch[MXN][27],pa[MXN],len[MXN],anc[MXN][P+3],root=1,last=1,pos[N],tail=1;
int Root[MXN],Tail=0,q,tx[MXN];
bool cmp(const int &A,const int &B){return len[A]<len[B];}
char s[N];
struct data
{
	int x,y;
	data(){}
	data(int x,int y):x(x),y(y){}
	data operator+(const data &B)
	{
		if(x==B.x) return data(x,y+B.y);
		if(y>B.y||(y==B.y&&x<B.x)) return data(x,y);
		else return data(B.x,B.y);
	}
	void pt(int ss){cout<<ss<<" : "<<x<<" "<<y<<endl;}
};
struct node
{
	int ls,rs;
	data p;
}tr[MXN*25];
void insert(int c)
{
	int nd=++tail; len[tail]=len[last]+1; int tmp=last;
	while(tmp&&!ch[tmp][c]) ch[tmp][c]=nd,tmp=pa[tmp];
	if(tmp==0) pa[nd]=root;
	else
	{
		int B=ch[tmp][c];
		if(len[B]==len[tmp]+1) pa[nd]=B;
		else
		{
			int nB=++tail; len[nB]=len[tmp]+1;
			for(int i=0;i<=26;i++) ch[nB][i]=ch[B][i];
			while(tmp&&ch[tmp][c]==B) ch[tmp][c]=nB,tmp=pa[tmp];
			pa[nB]=pa[B]; pa[B]=nB; pa[nd]=nB;
		}
	}
	last=nd;
}
void insert(int &nd,int lf,int rg,int pos)
{
	if(!nd) nd=++Tail,tr[nd].p=data(0,0);
	if(lf==rg)
	{
		if(!tr[nd].p.y) tr[nd].p=data(pos,1);
		else tr[nd].p.y++;
		return;
	}
	int mid=(lf+rg)>>1;
	if(pos<=mid) insert(tr[nd].ls,lf,mid,pos);
	else insert(tr[nd].rs,mid+1,rg,pos);
	tr[nd].p=tr[tr[nd].ls].p+tr[tr[nd].rs].p;
}
int merge(int x,int y,int lf,int rg)
{
	if(!x||!y) return x|y;
	int z=++Tail;
	if(lf==rg)
	{
		tr[z].p=tr[x].p+tr[y].p;
		return z;
	}
	int mid=(lf+rg)>>1;
	tr[z].ls=merge(tr[x].ls,tr[y].ls,lf,mid);
	tr[z].rs=merge(tr[x].rs,tr[y].rs,mid+1,rg);
	tr[z].p=tr[tr[z].ls].p+tr[tr[z].rs].p;
	return z;
}
void init()
{
	for(int i=1;i<=tail;i++) tx[i]=i;
	sort(tx+1,tx+tail+1,cmp);
	for(int j=tail;j>=1;j--)
	{
		int i=tx[j];
		if(pa[i]) Root[pa[i]]=merge(Root[pa[i]],Root[i],1,m);

	}
	for(int j=1;j<=tail;j++)
	{
		int i=tx[j];
		anc[i][0]=pa[i];
		for(int p=1;p<=P;p++) anc[i][p]=anc[anc[i][p-1]][p-1];
	}
}
data query(int nd,int lf,int rg,int L,int R)
{
	if(L<=lf&&rg<=R) return tr[nd].p;
	int mid=(lf+rg)>>1;
	data ret=data(0,0);
	if(L<=mid) ret=ret+query(tr[nd].ls,lf,mid,L,R);
	if(R>mid) ret=ret+query(tr[nd].rs,mid+1,rg,L,R);
	return ret;
}
int main()
{
//	freopen("out.out","w",stdout);
	scanf("%s",s+1); n=strlen(s+1);
	for(int i=1;i<=n;i++) insert(s[i]-'a'),pos[i]=last; insert(26);
	scanf("%d",&m);
	for(int j=1;j<=m;j++)
	{
		scanf("%s",s); int l=strlen(s);
		for(int i=0;i<l;i++)
		insert(s[i]-'a'),insert(Root[last],1,m,j);
		insert(26);
	}
	init();
	scanf("%d",&q);
	while(q--)
	{
		int l,r,L,R; scanf("%d%d%d%d",&l,&r,&L,&R);
		int x=pos[R];
		for(int i=P;i>=0;i--) if(len[anc[x][i]]>=R-L+1) x=anc[x][i];
		data u=query(Root[x],1,m,l,r);
		if(!u.y) printf("%d %d\n",l,0);
		else printf("%d %d\n",u.x,u.y);
	}
	return 0;
}


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=500005;
const int MXN=1200005;
const int P=20;
int n,m,ch[MXN][27],pa[MXN],len[MXN],anc[MXN][P+3],root=1,last=1,pos[N],tail=1;
int Root[MXN],Tail=0,q,tx[MXN];
bool cmp(const int &A,const int &B){return len[A]<len[B];}
char s[N];
struct data
{
	int x,y;
	data(){}
	data(int x,int y):x(x),y(y){}
	data operator+(const data &B)
	{
		if(x==B.x) return data(x,y+B.y);
		if(y>B.y||(y==B.y&&x<B.x)) return data(x,y);
		else return data(B.x,B.y);
	}
	void pt(int ss){cout<<ss<<" : "<<x<<" "<<y<<endl;}
};
struct node
{
	int ls,rs;
	data p;
}tr[MXN*25];
void insert(int c)
{
	int nd=++tail; len[tail]=len[last]+1; int tmp=last;
	while(tmp&&!ch[tmp][c]) ch[tmp][c]=nd,tmp=pa[tmp];
	if(tmp==0) pa[nd]=root;
	else
	{
		int B=ch[tmp][c];
		if(len[B]==len[tmp]+1) pa[nd]=B;
		else
		{
			int nB=++tail; len[nB]=len[tmp]+1;
			for(int i=0;i<=26;i++) ch[nB][i]=ch[B][i];
			while(tmp&&ch[tmp][c]==B) ch[tmp][c]=nB,tmp=pa[tmp];
			pa[nB]=pa[B]; pa[B]=nB; pa[nd]=nB;
		}
	}
	last=nd;
}
void insert(int &nd,int lf,int rg,int pos)
{
	if(!nd) nd=++Tail,tr[nd].p=data(0,0);
	if(lf==rg)
	{
		if(!tr[nd].p.y) tr[nd].p=data(pos,1);
		else tr[nd].p.y++;
		return;
	}
	int mid=(lf+rg)>>1;
	if(pos<=mid) insert(tr[nd].ls,lf,mid,pos);
	else insert(tr[nd].rs,mid+1,rg,pos);
	tr[nd].p=tr[tr[nd].ls].p+tr[tr[nd].rs].p;
}
int merge(int x,int y,int lf,int rg)
{
	if(!x||!y) return x|y;
	int z=++Tail;
	if(lf==rg)
	{
		tr[z].p=tr[x].p+tr[y].p;
		return z;
	}
	int mid=(lf+rg)>>1;
	tr[z].ls=merge(tr[x].ls,tr[y].ls,lf,mid);
	tr[z].rs=merge(tr[x].rs,tr[y].rs,mid+1,rg);
	tr[z].p=tr[tr[z].ls].p+tr[tr[z].rs].p;
	return z;
}
void init()
{
	for(int i=1;i<=tail;i++) tx[i]=i;
	sort(tx+1,tx+tail+1,cmp);
	for(int j=tail;j>=1;j--)
	{
		int i=tx[j];
		if(pa[i]) Root[pa[i]]=merge(Root[pa[i]],Root[i],1,m);

	}
	for(int j=1;j<=tail;j++)
	{
		int i=tx[j];
		anc[i][0]=pa[i];
		for(int p=1;p<=P;p++) anc[i][p]=anc[anc[i][p-1]][p-1];
	}
}
data query(int nd,int lf,int rg,int L,int R)
{
	if(L<=lf&&rg<=R) return tr[nd].p;
	int mid=(lf+rg)>>1;
	data ret=data(0,0);
	if(L<=mid) ret=ret+query(tr[nd].ls,lf,mid,L,R);
	if(R>mid) ret=ret+query(tr[nd].rs,mid+1,rg,L,R);
	return ret;
}
int main()
{
//	freopen("out.out","w",stdout);
	scanf("%s",s+1); n=strlen(s+1);
	for(int i=1;i<=n;i++) insert(s[i]-'a'),pos[i]=last; insert(26);
	scanf("%d",&m);
	for(int j=1;j<=m;j++)
	{
		scanf("%s",s); int l=strlen(s);
		for(int i=0;i<l;i++)
		insert(s[i]-'a'),insert(Root[last],1,m,j);
		insert(26);
	}
	init();
	scanf("%d",&q);
	while(q--)
	{
		int l,r,L,R; scanf("%d%d%d%d",&l,&r,&L,&R);
		int x=pos[R];
		for(int i=P;i>=0;i--) if(len[anc[x][i]]>=R-L+1) x=anc[x][i];
	//	printf("x=%d len=%d\n",x,len[x]);
		data u=query(Root[x],1,m,l,r);
		if(!u.y) printf("%d %d\n",1,0);
		else printf("%d %d\n",u.x,u.y);
	}
	return 0;
}


#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;
		    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;
	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);
	}
	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(pr<qy[ip].pl);
	    	for(;j<=qy[ip].pr;j=nxt[j])
	    	{
    		 //  assert(pos[j]>0);
    		 if(i==3155)
    		    printf("%d ",pos[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]]++;
        if(i==3155)
            printf("%d ",pos[j]);
        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'+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];
     }
     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>
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
	{
		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;
	    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)
	    	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<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;
		    //	printf("now.id=%d,it->id=%d\n",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);
		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])
	    	{
    		 //  assert(pos[j]>0);
    		// if(i==3155)
    		 //   printf("%d ",pos[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]]++;
       // if(i==3155)
        //    printf("%d ",pos[j]);
        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].pr;
}
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 N=600000;
char str[555555],tr[55555];
int m,len,n,lg[600000],pa[5010000],ans[2][510000],sz[510000],ix[510000],sum[55555];
int sa[N],X[N],Y[N],b[N],a[N],h[N],r[N],rnk[N],lcp[N],pos[N],nxt[N],pre[N],fk[19][N];
vector<int>adj[510000];
bool comp(int *r,int a,int b,int le)
{
		return r[a] == r[b] && r[a+le] == r[b+le];
}
void sort(int *Rank,int *Id,int n,int m)
{
		std::fill(b,b+m,0);
		for(int i = n-1; i >= 0; i--) b[Rank[i]]++;
		for(int i = 1; i < m; i++) b[i] += b[i-1];
		for(int i = n-1; i >= 0; i--) sa[--b[Rank[Id[i]]]] = Id[i];
}
void suffix(int n,int m=500)
{
		int *Rank = X, *Id = Y, p = 1;
		for(int i = 0; i < n; i++) Rank[i] = a[i], Id[i] = i;
		sort(Rank,Id,n,m);
		for(int j = 1; p < n; j <<= 1){
				p = 0;
				for(int i = n-j; i < n; i++) Id[p++] = i;
				for(int i = 0; i < n; i++) if(sa[i] >= j) Id[p++] = sa[i] - j;
				sort(Rank,Id,n,p);
				std::swap(Rank,Id);
				Rank[sa[0]] = 0, p = 1;
				for(int i = 1; i < n; i++)
						Rank[sa[i]] = comp(Id,sa[i-1],sa[i],j) ? p-1 : p++;
				m = p;
		}
}

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
	{
	    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++)
	   a[i]=str[i]+m+1;
    a[n++]='a'+m;
	for(i=0;i<m;i++)
	{
		gets(tr);
		sum[i]=n;
		len=strlen(tr);
		for(j=0;j<len;j++)
            a[n++]=tr[j]+m+1;
        a[n++]='a'+m-1-i;
	}
	sum[i]=n;
	a[n]=0;
	suffix(n+1);
	 for(i=1;i<=n;i++)
       sa[i-1]=sa[i];
	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(a);
	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

*/