#include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;
using ld = long double;
template<class t>
using table = vector<vector<t>>;
const ld eps = 1e-9;
#include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;
using ld = long double;
template<class T>
using Table = vector<vector<T>>;

struct Point3 {
	long double x;
	long double y;
	long double z;
	Point3() :x(0), y(0), z(0) {}
	Point3(const long double _x, const long double _y, const long double _z) :x(_x), y(_y), z(_z) {}
};

Point3 operator+(const Point3&l, const Point3& r) {
	return Point3(l.x + r.x, l.y + r.y, l.z + r.z);
}
Point3 operator+=(Point3&l, const Point3& r) {
	return l = Point3(l.x + r.x, l.y + r.y, l.z + r.z);
}
Point3 operator-(const Point3&l, const Point3& r) {
	return Point3(l.x - r.x, l.y - r.y, l.z - r.z);
}
Point3 operator-=(Point3&l, const Point3& r) {
	return l = Point3(l.x - r.x, l.y - r.y, l.z - r.z);
}
Point3 operator*(const Point3&l, const long double r) {
	return Point3(l.x * r, l.y * r, l.z * r);
}
Point3 operator*(const long double r, const Point3&l) {
	return l*r;
}
Point3 operator*=(Point3&l, const long double r) {
	return l = Point3(l.x * r, l.y * r, l.z * r);
}
Point3 operator/(const Point3&l, const long double r) {
	return Point3(l.x / r, l.y / r, l.z / r);
}
Point3 operator/=(Point3&l, const long double r) {
	return l = Point3(l.x / r, l.y / r, l.z / r);
}
const long double  pi = acos(-1.0);
const long double dtop = pi / 180.;
const long double ptod = 1. / dtop;

namespace std {
	bool operator<(const Point3 &lhs, const Point3 &rhs) {
		if (lhs.x< rhs.x - eps) return true;
		if (lhs.x > rhs.x + eps) return false;
		if (lhs.y< rhs.y - eps) return true;
		if (lhs.y > rhs.y + eps) return false;
		return lhs.z < rhs.z;
	}
}

// ????????\???
Point3 input_point() {
	long double x, y, z;
	cin >> x >> y >> z;
	return Point3(x, y, z);
}

// ????????????????????????
bool eq(const long double a, const long double b) {
	return (abs(a - b) < eps);
}

// ??????
long double dot(const Point3& a, const Point3& b) {
	return a.x*b.x + a.y*b.y + a.z*b.z;
}

// ??????
Point3 cross(const Point3& a, const Point3& b) {
	return Point3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);
}



//?????????
long double norm(const Point3&p) {
	return (p.x*p.x + p.y*p.y + p.z*p.z);
}

long double abs(const Point3&p) {

	return sqrt(p.x*p.x + p.y*p.y + p.z*p.z);
}
//?????????????????????
Point3 unit(const Point3& a) {
	return a / (abs(a));
}




//???
struct Sphere {
	Point3 p;
	long double r;
	Sphere() :p(), r(0) {}
	Sphere(const Point3 _point, const long double _radius) :p(_point), r(_radius) {}
};
/*  0 => out
1 => on
2 => in*/
int point_in_sphere(const Point3&p, const Sphere&s) {
	ld dis = abs(s.p - p);
	if (dis - eps > s.r)return 0;
	else if (dis + eps < s.r)return 2;
	else return 1;
}

//a ??? b ?????\??£????????????
int sphere_in_sphere(const Sphere&a, const Sphere&b) {
	if (!point_in_sphere(a.p, b))return 0;
	else {
		ld dis = abs(a.p - b.p);
		if (a.r + dis - eps>b.r)return 0;
		else if (a.r + dis + eps < b.r)return 2;
		else return 1;
	}
}

// ??´????????????
class Line3 {
public:
	Point3 a, b;
	Line3() : a(Point3(0, 0, 0)), b(Point3(0, 0, 0)) {}
	Line3(Point3 a, Point3 b) : a(a), b(b) {}
	Point3 operator[](const int _num)const {
		if (_num == 0)return a;
		else if (_num == 1)return b;
		else assert(false);
	}
};

// ?????????????????????
bool isis_sp(const Line3& s, const Point3& p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}

// ??????????¶?
Point3 proj(const Line3 &l, const Point3& p) {
	long double t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
// ??´?????¨???????????¢
long double dist_lp3(const Line3& l, const Point3& p) {
	return abs(p - proj(l, p));
}
// ?????¨??´????????????
vector<Point3> is_lsp(const Sphere& c, const Line3& l) {
	vector<Point3> res;
	long double d = dist_lp3(l, c.p);
	if (d < c.r + eps) {
		long double len = (d > c.r) ? 0.0 : sqrt(c.r * c.r - d * d); //safety;
		Point3 nor = (l.a - l.b) / abs(l.a - l.b);
		res.push_back(proj(l, c.p) + len * nor);
		res.push_back(proj(l, c.p) - len * nor);
	}
	return res;
}
// ?????¨???????????????
vector<Point3> is_ssp(const Sphere& c, const Line3& l) {
	vector<Point3> res(is_lsp(c, l));
	vector<Point3> nres;
	for (auto p : res) {
		if (isis_sp(l, p))nres.emplace_back(p);
	}
	return nres;
}
// ????????????????????¢(??????)??§???????°?
Point3 reflect(const Point3& vec, const Point3& no) {
	return vec - 2 * dot(vec, no) / abs(no)*unit(no);

}


struct UnionFind {
	vector<int> data;
	UnionFind(int size) : data(size, -1) { }
	bool unionSet(int x, int y) {
		x = root(x); y = root(y);
		if (x != y) {
			if (data[y] < data[x]) swap(x, y);
			data[x] += data[y]; data[y] = x;
		}
		return x != y;
	}
	bool findSet(int x, int y) {
		return root(x) == root(y);
	}
	int root(int x) {
		return data[x] < 0 ? x : data[x] = root(data[x]);
	}
	int size(int x) {
		return -data[root(x)];
	}
};


// a binary predicate implemented as a function:
bool same_integral_part(double first, double second)
{
	return (abs((first)-(second))<eps);
}

int main() {
	while (1) {

		int N; cin >> N;
		if (!N)break;
		vector<Sphere>sps;
		for (int i = 0; i < N; ++i) {

			ld x, y, z, r; cin >> x >> y >> z >> r;
			Sphere sp(Point3(x, y, z), r);
			sps.emplace_back(sp);
		}
		vector<ld>nums;
		for (int i = 0; i < N; ++i) {
			for (int j = i + 1; j < N; ++j) {
				ld aminz, amaxz;
				if (sphere_in_sphere(sps[i], sps[j])) {
				}
				else if (sphere_in_sphere(sps[j], sps[i])) {
				}
				else {
					ld dis = abs(sps[j].p - sps[i].p);
					Point3 center = (sps[i].p + sps[j].p) / 2;

					if (dis - eps > sps[j].r + sps[i].r)continue;
					else {

						{
							ld amin = max(sps[i].p.z - sps[i].r, sps[j].p.z - sps[j].r) + eps;
							ld amax = ((sps[i].p.z + sps[j].p.z) - (sps[i].p.z - sps[j].p.z) * (sps[i].r - sps[j].r) / dis) / 2.0;

							int num = 50;
							ld disxy = sqrt(powl(sps[i].p.x - sps[j].p.x, 2) + powl(sps[i].p.y - sps[j].p.y, 2));
							while (num--) {
								ld amid = (amin + amax) / 2;
								ld ir = sqrt(sps[i].r*sps[i].r - powl(sps[i].p.z - amid, 2));
								ld jr = sqrt(powl(sps[j].r, 2) - powl(sps[j].p.z - amid, 2));
								if (ir + jr < disxy) {
									amin = amid;
								}
								else {
									amax = amid;
								}
							}
							aminz = amin;
						}
						{
							ld amax = min(sps[i].p.z + sps[i].r, sps[j].p.z + sps[j].r) + eps;
							ld amin = ((sps[i].p.z + sps[j].p.z) - (sps[i].p.z - sps[j].p.z) * (sps[i].r - sps[j].r) / dis) / 2.0;

							int num = 50;
							ld disxy = sqrt(powl(sps[i].p.x - sps[j].p.x, 2) + powl(sps[i].p.y - sps[j].p.y, 2));
							while (num--) {
								ld amid = (amin + amax) / 2;
								ld ir = sqrt(sps[i].r*sps[i].r - powl(sps[i].p.z - amid, 2));
								ld jr = sqrt(powl(sps[j].r, 2) - powl(sps[j].p.z - amid, 2));
								if (ir + jr > disxy) {
									amin = amid;
								}
								else {
									amax = amid;
								}
							}
							amaxz = amax;
						}
						
					}
				}
				nums.emplace_back(aminz);
				nums.emplace_back(amaxz);
				
			}
			nums.emplace_back(sps[i].p.z - sps[i].r);
			nums.emplace_back(sps[i].p.z + sps[i].r);
		}
		nums.emplace_back(-1);
		nums.emplace_back(100000);
		sort(nums.begin(), nums.end());
		nums.erase(unique(nums.begin(), nums.end(), same_integral_part),nums.end());

		vector<int>anss;
		for (int i = 0; i < nums.size()-1; ++i) {
			ld az = (nums[i] + nums[i + 1]) / 2;
			UnionFind uf(N);
			vector<int>valids(N);
			for (int j = 0; j < N; ++j) {
				if (az >= sps[j].p.z- sps[j].r&&az <= sps[j].p.z + sps[j].r)valids[j] = true;
			}
			for (int j = 0; j < N; ++j)
			{
				for (int k = j+1; k < N; ++k) {
					if (valids[j] && valids[k]) {
						ld disxy = sqrt(powl(sps[k].p.x - sps[j].p.x, 2) + powl(sps[k].p.y - sps[j].p.y, 2));

						ld kr = sqrt(sps[k].r*sps[k].r - powl(sps[k].p.z - az, 2));
						ld jr = sqrt(powl(sps[j].r, 2) - powl(sps[j].p.z - az, 2));
						if (kr + jr > disxy) {
							uf.unionSet(j, k);
						}
						else {
						}
					}
				}
			}
			set<int>aset;
			for (int j = 0; j < N; ++j) {
				if (valids[j])aset.emplace(uf.root(j));
			}
			anss.emplace_back(aset.size());
		}
		string st;
		for (int i = 0; i < anss.size() - 1; ++i) {
			if (anss[i + 1] == anss[i] + 1)st += '1';
			else if (anss[i + 1] + 1 == anss[i])st += '0';

		}
		cout << st.size() << endl << st << endl;
	}

	return 0;
}

Measured memory_bytes: 3532