#include <bits/stdc++.h>
using namespace std;
template <typename T>
inline bool chkmin(T &x, T y) {
  return y < x ? x = y, 1 : 0;
}
template <typename T>
inline bool chkmax(T &x, T y) {
  return x < y ? x = y, 1 : 0;
}
const int INF = 0x3f3f3f3f;
const int N = 5e5 + 10, M = 5e4 + 10, Node = (N + M) << 1;
string procStatus() {
  ifstream t("/proc/self/status");
  return string(istreambuf_iterator<char>(t), istreambuf_iterator<char>());
}
char str[N], S[N];
struct Item {
  int L, R, l, id;
};
vector<Item> Opt[N];
struct Query {
  int l, r, id;
};
vector<Query> Q[Node];
struct Ans {
  int id, cnt;
  bool operator<(const Ans &rhs) const {
    return cnt == rhs.cnt ? id > rhs.id : cnt < rhs.cnt;
  }
} ans[N];
int to[Node], nex[Node], beg[Node], F[Node][21], rt[Node];
int e, m;
inline int read() {
  int x = 0, flag = 1;
  char ch = getchar();
  while (!isdigit(ch) && ch != '-') ch = getchar();
  if (ch == '-') flag = -1, ch = getchar();
  while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch - '0'), ch = getchar();
  return x * flag;
}
struct Segment_tree {
  int ls[M * 20], rs[M * 20];
  Ans Max[M * 20];
  int node;
  inline void Modify(int &o, int l, int r, int pos) {
    if (!o) o = ++node;
    if (l == r) {
      Max[o].id = ((l + r) >> 1), Max[o].cnt++;
      return;
    }
    if (pos <= ((l + r) >> 1))
      Modify(ls[o], l, ((l + r) >> 1), pos);
    else
      Modify(rs[o], ((l + r) >> 1) + 1, r, pos);
    Max[o] = max(Max[ls[o]], Max[rs[o]]);
  }
  inline int Merge(int x, int y) {
    if (!x || !y) return x + y;
    ls[x] = Merge(ls[x], ls[y]);
    rs[x] = Merge(rs[x], rs[y]);
    if (Max[x].id == Max[y].id)
      Max[x].cnt += Max[y].cnt;
    else
      Max[x] = max(Max[ls[x]], Max[rs[x]]);
    return x;
  }
  inline Ans Query(int o, int l, int r, int L, int R) {
    if (!o) return (Ans){0, 0};
    if (L <= l && r <= R) return Max[o];
    Ans cur = (Ans){0, 0};
    if (L <= ((l + r) >> 1))
      cur = max(cur, Query(ls[o], l, ((l + r) >> 1), L, R));
    if (R > ((l + r) >> 1))
      cur = max(cur, Query(rs[o], ((l + r) >> 1) + 1, r, L, R));
    return cur;
  }
} Seg;
struct Suffix_Automaton {
  int trans[Node][26], link[Node], len[Node];
  int cnt, las;
  Suffix_Automaton() { cnt = las = 1; }
  inline void Extend(int id, int type) {
    int np = ++cnt, p = las;
    len[np] = len[p] + 1;
    if (type) Seg.Modify(rt[np], 1, m, type);
    for (; p && !trans[p][id]; p = link[p]) trans[p][id] = np;
    if (!p)
      link[np] = 1;
    else {
      int q = trans[p][id];
      if (len[q] == len[p] + 1)
        link[np] = q;
      else {
        int nq = ++cnt;
        len[nq] = len[p] + 1, link[nq] = link[q];
        memcpy(trans[nq], trans[q], sizeof(trans[q]));
        for (; p && trans[p][id] == q; p = link[p]) trans[p][id] = nq;
        link[q] = link[np] = nq;
      }
    }
    las = trans[las][id];
  }
} Sam;
inline void add(int x, int y) { to[++e] = y, nex[e] = beg[x], beg[x] = e; }
inline void dfs(int x, int fa) {
  F[x][0] = fa;
  for (int i = beg[x]; i; i = nex[i]) {
    if (to[i] == fa) continue;
    dfs(to[i], x);
  }
}
inline void Dfs(int x, int fa) {
  for (int i = beg[x]; i; i = nex[i]) {
    if (to[i] == fa) continue;
    Dfs(to[i], x);
    rt[x] = Seg.Merge(rt[x], rt[to[i]]);
  }
  for (int i = (0), iend = (Q[x].size() - 1); i <= iend; i++) {
    ans[Q[x][i].id] = Seg.Query(rt[x], 1, m, Q[x][i].l, Q[x][i].r);
    if (!ans[Q[x][i].id].cnt) ans[Q[x][i].id].id = Q[x][i].l;
  }
}
int main() {
  scanf("%s", S + 1);
  int s = strlen(S + 1);
  m = read();
  int id = 0;
  for (int i = (1), iend = (s); i <= iend; i++) Sam.Extend(S[i] - 'a', 0);
  for (int i = (1), iend = (m); i <= iend; i++) {
    Sam.las = 1, id++;
    scanf("%s", str + 1);
    int len = strlen(str + 1);
    for (int j = (1), jend = (len); j <= jend; j++)
      Sam.Extend(str[j] - 'a', id);
  }
  int q = read();
  for (int i = (1), iend = (q); i <= iend; i++) {
    int L = read(), R = read(), l = read(), r = read();
    Opt[r].push_back((Item){L, R, l, i});
  }
  for (int i = (2), iend = (Sam.cnt); i <= iend; i++) add(Sam.link[i], i);
  dfs(1, 0);
  for (int i = (1), iend = (20); i <= iend; i++)
    for (int j = (1), jend = (Sam.cnt); j <= jend; j++)
      F[j][i] = F[F[j][i - 1]][i - 1];
  int pos = 1;
  for (int i = (1), iend = (s); i <= iend; i++) {
    pos = Sam.trans[pos][S[i] - 'a'];
    for (int j = (0), jend = (Opt[i].size() - 1); j <= jend; j++) {
      int cur = pos, Aim = i - Opt[i][j].l + 1;
      for (int k = (20), kend = (0); k >= kend; k--)
        if (F[cur][k] && Sam.len[F[cur][k]] >= Aim) cur = F[cur][k];
      Q[cur].push_back((Query){Opt[i][j].L, Opt[i][j].R, Opt[i][j].id});
    }
  }
  Dfs(1, 0);
  for (int i = (1), iend = (q); i <= iend; i++)
    printf("%d %d\n", ans[i].id, ans[i].cnt);
  return 0;
}
