import java.awt.geom.*;
import java.io.*;
import java.util.*;

import javax.management.ReflectionException;

//reference rankalee's code
public class Main {
	double EPS = 1.0e-08;
	
	class P{
		double [] p;
		public P(double[] p) {
			this.p = new double[3];
			for(int i =0; i < 3; i++){
				this.p[i] = p[i];
			}
			this.p = p;
		}
	}
	
	class Line{
		P p1, p2;

		public Line(P p1, P p2) {
			this.p1 = p1;
			this.p2 = p2;
		}
		
	}
	
	private void doit(){
		Scanner sc = new Scanner(System.in);
		while(true){
			int n = sc.nextInt();
			if(n == 0)break;
			double [] input = new double[3];
			for(int i = 0; i < 3; i++) input[i] = sc.nextInt();
			P last = new P(new double[3]);
			P dir = new P(input);
			P [] data = new P[n];
			double [] rlist = new double[n];
			for(int i = 0; i < n; i++){
				double [] temp = new double[3];
				temp[0] = sc.nextInt();
				temp[1] = sc.nextInt();
				temp[2] = sc.nextInt();
				data[i] = new P(temp);
				rlist[i] = sc.nextInt();
			}
			while(true){
				double mn = 1 << 24;
				int mni = -1;
				Line l = new Line(last, dir);
				for(int i = 0; i < n; i++){
					double disL = distanceLP(l, data[i]);
					if(disL >= rlist[i]) continue;
					double lo = 0, mid = -1;
					double hi = dot(sub(data[i], l.p1), sub(l.p2, l.p1)) / norm(sub(l.p2, l.p1));
					for(int it = 0; it < 100; it++){
						mid = (lo + hi) /2;
						if(abs(sub(add(l.p1, mul(mid,(sub(l.p2, l.p1)))), data[i])) < rlist[i]){
							hi = mid;
						}
						else{
							lo = mid;
						}
					}
					if(lo < EPS )continue;
					if(mn > mid){
						mn = mid;
						mni = i;
					}
					

					
				}
				if(mni == -1){
					break;
				}
				P nextdist = add(last, mul(mn, sub(dir, last)));
				Line midLine = new Line(data[mni], nextdist);
				P nextterm = reflection(midLine, last);
				last = new P(nextdist.p.clone());
				dir = new P(nextterm.p.clone());
			}
			System.out.printf("%.4f %.4f %.4f\n",last.p[0],last.p[1],last.p[2] );
		}
	}

	private P reflection(Line l, P p) {
		return add(p, mul(2.0, sub(projection(l,p) , p)));
	}

	private double distance(P p1, P p2) {
		double res = 0;
		for(int i = 0; i < 3; i++){
			res += (p1.p[i] - p2.p[i]) * (p1.p[i] - p2.p[i]);
		}
		return Math.sqrt(res);
	}

	private double distanceLP(Line l, P p) {
		return abs(sub(p, projection(l,p)));
	}

	private double abs(P p) {
		return Math.sqrt(norm(p));
	}

	private double norm(P p) {
		return dot(p,p);
	}

	private double dot(P p1, P p2) {
		double res = 0.0;
		for(int i = 0; i < 3; i++){
			res += p1.p[i] * p2.p[i];
		}
		return res;
	}

	private P sub(P p1, P p2) {
		double [] res = new double[3];
		for(int i = 0; i < 3; i++){
			res[i] = p1.p[i] - p2.p[i];
		}
		return new P(res);
	}

	private P projection(Line l, P p) {
		double t = dot(sub(p, l.p1), sub(l.p1, l.p2)) / norm(sub(l.p1, l.p2));
		return add(l.p1, mul(t, (sub(l.p1, l.p2))));
	}

	private P add(P p1, P p2) {
		double [] res = new double[3];
		for(int i = 0; i < 3; i++){
			res[i] = p1.p[i] + p2.p[i];
		}
		return new P(res);
	}

	private P mul(double t, P p) {
		double [] res = new double[3];
		for(int i = 0; i < 3; i++){
			res[i] = p.p[i] * t;
		}
		return new P(res);
	}

	public static void main(String [] args){
		new Main().doit();
	}
}

Measured memory_bytes: 13000