#include "bits/stdc++.h"
using namespace std;
using ld = long double;
const ld eps = 1e-9;

ld getdis(vector<ld>&l, vector<ld>&r) {
	ld sum = 0;
	for (int i = 0; i < 3; ++i) {
		sum += (l[i] - r[i])*(l[i] - r[i]);
	}
	return sqrt(sum);
}

struct po {
	int index;
	vector<ld> coors;
	po(int _d) :coors(_d) {
		index = -1;
	}
	po(int _index, vector<ld>_coors) :index(_index), coors(_coors) {

	}
	po() {}
};
ld getdis(po&lpo, po&rpo) {
	return getdis(lpo.coors, rpo.coors);
}
template<class T>
class axisSorter {
	int k;
public:
	axisSorter(int _k) : k(_k) {}
	bool operator()(const T &a, const T &b) {
		return a.coors[k] < b.coors[k];
	}
};



struct Ans {
	ld dis;
	pair<int, int>p;

};


bool operator<(const Ans&l, const Ans&r) {
	if (abs(l.dis - r.dis) < eps) {
		assert(l.p.first < l.p.second);
		assert(r.p.first < r.p.second);
		return l.p < r.p;
	}
	else {
		return l.dis < r.dis;
	}
	return true;
}
Ans answer;

template<class T, int Dim = 3>
struct kdtree {
public:
	T midpo;
	vector<T>pos;
	shared_ptr<kdtree<T>> ltree, rtree;
	int depth;
	int axis;
	kdtree(const T &p_) :midpo(p_), ltree(), rtree() {

	}
	~kdtree() {
	}

	kdtree(vector<T>&ps_, const int& l, const int& r, const int depth_ = 0) : ltree(nullptr), rtree(nullptr), depth(depth_), axis(depth%Dim) {
		init(ps_, l, r);
	}
	void getmindis() {
		vector<po>lpos, rpos;
		ld axisvalue = midpo.coors[axis];

		if (ltree != nullptr) {
			for (auto &po : ltree->pos) {
				if (po.coors[axis]>axisvalue - sqrt(answer.dis) - eps * 10) {
					lpos.emplace_back(po);
				}
			}
		}
		if (rtree != nullptr) {
			for (auto &po : rtree->pos) {
				if (po.coors[axis]<axisvalue + sqrt(answer.dis) + eps * 10) {
					rpos.emplace_back(po);
				}
			}
		}

		for (auto& lpo : lpos) {
			for (auto& rpo : rpos) {
				ld dis = getdis(lpo, rpo);
				pair<int, int> p(rpo.index, lpo.index);
				if (p.first > p.second)swap(p.first, p.second);
				Ans nans{ dis,p };
				answer = min(answer, nans);
			}
			{
				ld dis = getdis(lpo, midpo);
				pair<int, int> p(midpo.index, lpo.index);
				if (p.first > p.second)swap(p.first, p.second);
				Ans nans{ dis,p };
				answer = min(answer, nans);
			}
		}
		for (auto& rpo : rpos) {
			ld dis = getdis(midpo, rpo);
			pair<int, int> p(midpo.index, rpo.index);
			if (p.first > p.second)swap(p.first, p.second);
			Ans nans{ dis,p };
			answer = min(answer, nans);
		}
	}
private:
	void init(vector<T>&ps, const int& l, const int& r) {
		if (l >= r) {
			return;
		}
		const int mid = (l + r) / 2;
		nth_element(ps.begin() + l, ps.begin() + mid, ps.begin() + r, axisSorter<T>(axis));
		midpo = ps[mid];

		ltree = make_kdtree(ps, l, mid, depth + 1);
		
		rtree = make_kdtree(ps, mid + 1, r, depth + 1);
		getmindis();
		ltree.reset();
		rtree.reset();
		pos = vector<T>(ps.begin() + l, ps.begin() + r);
	}
};


//[l..r)
template<class T>
unique_ptr<kdtree<T>>make_kdtree(vector<T>&ps_, const int& l, const int& r, const int& depth = 0) {
	if (l >= r)return nullptr;
	else {
		return make_unique<kdtree<T>>(ps_, l, r, depth);
	}
}

vector<ld>getunit(vector<int>v) {
	vector<ld>unit;
	ld len = 0;
	for (auto&&a : v) {
		len += a*a;
		unit.emplace_back(ld(a));
	}
	len = sqrt(len);
	for (auto&u : unit) {
		u /= len;
	}
	return unit;
}
int gcd(int l, int r) {
	assert(l > 0 && r > 0);
	if (l > r)return gcd(r, l);
	else {
		const  int num = r%l;
		if (num) {
			return gcd(l, num);
		}
		else {
			return l;
		}
	}
}
int gcd(vector<int>nums) {
	if (nums.size() == 1)return nums[0];
	int num = nums[0];

	for (int i = 1; i < nums.size(); ++i) {
		num = gcd(num, nums[i]);
	}
	return num;
}

int main() {
	while (1) {
		answer = Ans{ 1e18,make_pair(-1,-1) };
		int M, N, S, W; cin >> M >> N >> S >> W;
		if (!M&&!N&&!S&&!W)break;
		vector<po>pos;
		vector<vector<int>>memo;
		{
			{
				int nx, ny, nz;
				for (int i = 0; i < M; ++i) {
					cin >> nx >> ny >> nz;
					memo.push_back(vector<int>{nx, ny, nz});
				}
				int g = S;
				for (int i = M; i < M + N; ++i) {
					nx = (g / 7) % 100 + 1;
					ny = (g / 700) % 100 + 1;
					nz = (g / 70000) % 100 + 1;
					memo.push_back(vector<int>{nx, ny, nz});
					if (g % 2 == 0)g = g / 2;
					else g = (g / 2) ^ W;
				}
			}
			sort(memo.begin(), memo.end(), [](const vector<int>&l, const vector<int>&r) {
				for (int i = 0; i < 3; ++i) {
					if (l[i] == r[i])continue;
					else return l[i] < r[i];
				}
				return false;
			});
			{
				vector<vector<int>>newmemo;
				map<vector<int>, int>amap;
				for (int i = 0; i < memo.size(); ++i) {
					int agcd = gcd(memo[i]);
					vector<int>v(3);
					for (int j = 0; j < 3; ++j)v[j] = memo[i][j] / agcd;
					if (amap.find(v) == amap.end() || amap[v] > agcd) {
						amap[v] = agcd;
					}
				}
				for (auto m : amap) {
					auto v = m.first;
					for (int i = 0; i < 3; ++i) {
						v[i] *= m.second;
					}
					newmemo.emplace_back(v);
				}
				memo = newmemo;
			}
			sort(memo.begin(), memo.end(), [](const vector<int>&l, const vector<int>&r) {
				for (int i = 0; i < 3; ++i) {
					if (l[i] == r[i])continue;
					else return l[i] < r[i];
				}
				return false;
			});
			for (int i = 0; i < memo.size(); ++i) {
				po p(i, getunit(memo[i]));
				pos.emplace_back(p);
			}
		}

		auto tree = make_kdtree(pos, 0, pos.size(), 0);
		tree->getmindis();
		auto ansp = answer;
		if (ansp.p.first >ansp.p.second)swap(ansp.p.first, ansp.p.second);
		for (int i = 0; i < 3; ++i) {
			cout << memo[answer.p.first][i] << " ";
		}
		for (int i = 0; i < 3; ++i) {
			cout << memo[answer.p.second][i];
			if (i == 2)cout << endl;
			else cout << " ";
		}
	}
	return 0;
}

Measured memory_bytes: 26912