#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <ctime>
#include <queue>
#include <stack>
#include <algorithm>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <deque>
#include <complex>
#include <string>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <valarray>
#include <iterator>
using namespace std;
typedef long long int ll;
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<int> vi;

#define REP(i,x) for(int i=0;i<(int)(x);i++)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++)
#define RREP(i,x) for(int i=((int)(x)-1);i>=0;i--)
#define RFOR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();i++)
#define ALL(container) container.begin(), container.end()
#define RALL(container) container.rbegin(), container.rend()
#define SZ(container) ((int)container.size())
#define mp(a,b) make_pair(a, b)
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );

template<class T> bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T> bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; }
template<class T> ostream& operator<<(ostream &os, const vector<T> &t) {
os<<"["; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"]"; return os;
}
template<class T> ostream& operator<<(ostream &os, const set<T> &t) {
os<<"{"; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"}"; return os;
}
template<class S, class T> ostream& operator<<(ostream &os, const pair<S,T> &t) { return os<<"("<<t.first<<","<<t.second<<")";}

const int INF = 1<<28;
const double EPS = 1e-8;
const int MOD = 1000000007;


#define EPS 1.0e-10
inline int signum(double x) { return (abs(x) < EPS ? 0 : x > 0 ? 1 : -1); }

struct P{
	double x, y, z;
	P():x(0),y(0),z(0){}
	P(double a, double b, double c):x(a),y(b),z(c){}
	
	P operator+(const P &opp){
		return P(x+opp.x, y+opp.y, z+opp.z);
	}
	P operator-(const P &opp){
		return P(x-opp.x, y-opp.y, z-opp.z);
	}
	P operator/(const P &opp){
		return P(abs(opp.x)<EPS?0:x/opp.x, abs(opp.y)<EPS?0:y/opp.y, abs(opp.z)<EPS?0:z/opp.z);
	}
	P operator/(const double &opp){
		return P(x/opp, y/opp, z/opp);
	}
	P operator*(const double opp){
		return P(x*opp, y*opp, z*opp);
	}
	friend ostream& operator<<(ostream &os, const P &t) { return os<<"("<<t.x<<","<<t.y<<","<<t.z<<")";}
};

struct L{
	P pos, dir;
	L(){}
	L(P p, P d):pos(p),dir(d){}
	L(P d):pos(),dir(d){}
};

struct C{
	P p;
	double r;
	C(){}
	C(P q, double s):p(q),r(s){}
};

inline double inp(P v1, P v2){
	return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
}

inline P outp(P p1, P p2){
	return P(p1.y*p2.z - p1.z*p2.y, p1.z*p2.x - p1.x*p2.z, p1.x*p2.y - p1.y*p2.x);
}

inline double norm(P v){
	return v.x*v.x + v.y*v.y + v.z*v.z;
}
inline double abs(P v){
	return sqrt(norm(v));
}

inline P perf(P v1, L l){
	return l.pos + l.dir*(inp(v1-l.pos, l.dir)/norm(l.dir));
}

bool lp_intersect(L l, P t){	// 点が直線上にあるかどうか
	return !signum(norm(outp(t-l.pos, l.dir)));
}

bool sp_intersect(L l, P t){	// 点が線分上にあるかどうか
	P a(t-l.pos), b(l.dir);
	if(signum(norm(a)) == 0 || signum(norm(a-b)) == 0) return true;	// 端点
	if(signum(norm(outp(a, b)))) return false;	// 直線上にない
	if(signum(a.x*b.x) == -1 || signum(a.y*b.y) == -1 || signum(a.z*b.z) == -1) return false;	// 逆方向
	if(norm(a) < norm(b)) return true;
	return false;	// イキスギィ！
}

double sp_distance(L l, P t){
	P v1 = t-l.pos;
	P v2 = perf(v1, L(l.dir));
	if(sp_intersect(L(l.dir), v2)) return abs(v1 - v2);
	else return sqrt(min(norm(t-l.pos), norm(t-(l.pos + l.dir))));
}

double sp_distance(P t, P p1, P p2){
	return sp_distance(L(p1, p2-p1), t);
}

vector<P> cl_crosspoint(C c, L l){
	P p = perf(c.p, l);
	double d2 = norm(c.p-p);
	if(d2 > c.r*c.r + EPS) return vector<P>();
	if(d2 > c.r*c.r - EPS) return vector<P>(1, p);	//境界
	double s = sqrt(c.r*c.r - d2);
	vector<P> ret;
	ret.push_back(p + l.dir/abs(l.dir)*s);
	ret.push_back(p - l.dir/abs(l.dir)*s);
	return ret;
}

vector<P> cs_crosspoint(C c, L l){
	vector<P> ret, res = cl_crosspoint(c, l);
	REP(i, res.size()) if(sp_intersect(l, res[i])) ret.push_back(res[i]);
	return ret;
}

bool cl_intersect(C c, L l){
	return sp_distance(l, c.p) < c.r + EPS;	// 境界を含む
}

bool cs_intersect(C c, L l){
	return !cs_crosspoint(c, l).empty();
}

P reflect(P p, L l){
	P q = perf(p, l);
	return q + (q - p);
}


int n;

main(){
	int i,j;
	while(cin >> n, n){
		vector<C> c;
		double x, y, z, r;
		cin >> x >> y >> z;
		L s(P(x*100, y*100, z*100));
		REP(i, n){
			cin >> x >> y >> z >> r;
			c.push_back(C(P(x, y, z), r));
		}
		P ans(0, 0, 0);
		while(1){
			pair<double, L> csp(1e10, L());
//			cout << "s: " << s.pos << " -> " << s.dir << endl;
			REP(i, n){
				vector<P> ret = cs_crosspoint(c[i], s);
				REP(j, ret.size()){
					if(norm(ret[j] - s.pos) > EPS && csp.first > norm(ret[j] - s.pos))
						csp = pair<double, L>(norm(ret[j] - s.pos), L(ret[j], c[i].p-ret[j]));
				}
			}
			if(csp.first > 1e9) break;
			ans = csp.second.pos;
			P ref = reflect(s.pos, csp.second);
//			cout << "reflect: " << ans << endl;
//			cout << "d: " << ref << endl;
			s = L(csp.second.pos, ref - csp.second.pos);
			s.dir = s.dir/abs(s.dir)*1000;
		}
		printf("%.4f %.4f %.4f\n", ans.x, ans.y, ans.z);
	}
	return 0;
}

Measured memory_bytes: 1264