#include <bits/stdc++.h>
using namespace std;
struct SegTree {
  struct Node {
    long long x = INT_MAX;
    void apply(int s, int e, long long v) { x = v; }
  };
  inline Node combine(const Node& a, const Node& b) {
    Node res;
    res.x = min(a.x, b.x);
    return res;
  }
  inline void push(int sn, int s, int e) {}
  int start, end;
  vector<Node> tree;
  void build(int sn, int s, int e) {
    if (s == e) {
      return;
    }
    int m = (s + e) >> 1, lsn = sn * 2, rsn = sn * 2 + 1;
    build(lsn, s, m);
    build(rsn, m + 1, e);
    tree[sn] = combine(tree[lsn], tree[rsn]);
  }
  template <typename T>
  void build(int sn, int s, int e, const vector<T>& v) {
    if (s == e) {
      tree[sn].x = v[s];
      return;
    }
    int m = (s + e) >> 1, lsn = sn * 2, rsn = sn * 2 + 1;
    build(lsn, s, m, v);
    build(rsn, m + 1, e, v);
    tree[sn] = combine(tree[lsn], tree[rsn]);
  }
  template <typename... T>
  void update(int sn, int s, int e, int qs, int qe, const T&... v) {
    if (qs <= s && e <= qe) {
      tree[sn].apply(s, e, v...);
      return;
    }
    int m = (s + e) >> 1, lsn = sn * 2, rsn = sn * 2 + 1;
    push(sn, s, e);
    if (qs <= m) update(lsn, s, m, qs, qe, v...);
    if (qe > m) update(rsn, m + 1, e, qs, qe, v...);
    tree[sn] = combine(tree[lsn], tree[rsn]);
  }
  Node query(int sn, int s, int e, int qs, int qe) {
    if (qs <= s && e <= qe) return tree[sn];
    int m = (s + e) >> 1, lsn = sn * 2, rsn = sn * 2 + 1;
    push(sn, s, e);
    if (qe <= m) return query(lsn, s, m, qs, qe);
    if (qs > m) return query(rsn, m + 1, e, qs, qe);
    return combine(query(lsn, s, m, qs, qe), query(rsn, m + 1, e, qs, qe));
  }
  void query(int sn, int s, int e, int qs, int qe,
             const function<void(Node&, int, int)>& f) {
    if (qs <= s && e <= qe) return f(tree[sn], s, e);
    int m = (s + e) >> 1, lsn = sn * 2, rsn = sn * 2 + 1;
    push(sn, s, e);
    if (qs <= m) query(lsn, s, m, qs, qe, f);
    if (qe > m) query(rsn, m + 1, e, qs, qe, f);
  }
  SegTree(int n) : SegTree(0, n - 1) {}
  SegTree(int _start, int _end) : start(_start), end(_end) {
    int n = end - start + 1;
    int maxs = n == 1 ? 2 : 1 << (33 - __builtin_clz(n - 1));
    tree.resize(maxs);
    build(1, start, end);
  }
  template <typename T>
  SegTree(const vector<T>& v) {
    int n = v.size();
    int maxs = n == 1 ? 2 : 1 << (33 - __builtin_clz(n - 1));
    tree.resize(maxs);
    start = 0;
    end = n - 1;
    build(1, start, end, v);
  }
  Node query(int qs, int qe) { return query(1, start, end, qs, qe); }
  Node query(int p) { return query(1, start, end, p, p); }
  void query(int qs, int qe, const function<void(Node&, int, int)>& f) {
    if (qs > qe) return;
    query(1, start, end, qs, qe, f);
  }
  template <typename... T>
  void update(int qs, int qe, const T&... v) {
    update(1, start, end, qs, qe, v...);
  }
};
int main() {
  int n, m;
  long long L, R;
  scanf("%d%d%lld%lld", &n, &m, &L, &R);
  vector<vector<int>> ans(n + 1);
  SegTree st(1, m);
  for (int a = n; a >= 1; --a) {
    for (int x = a; x <= n; x += a) {
      long long mn = 1, mx = m;
      mn = max((long long)mn, (L + x - 1) / x);
      mx = min((long long)mx, R / x);
      if (mn > mx) continue;
      int b = st.query(mn, mx).x;
      if (b == INT_MAX) continue;
      assert(b > a);
      long long x2 = (long long)b * (x / a);
      if (x2 > n) continue;
      int y = mx / b * b;
      assert(y >= mn);
      int y2 = (long long)x * y / x2;
      ans[x] = {x, y, (int)x2, y2};
    }
    for (int i = a; i <= m; i += a) {
      st.update(i, i, a);
    }
  }
  for (int x = 1; x <= n; ++x) {
    if (ans[x].empty())
      printf("-1\n");
    else {
      for (int i : ans[x]) printf("%d ", i);
      printf("\n");
    }
  }
}
