#include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 105
#define ADD EPS

struct Point{
	Point(double arg_x,double arg_y,double arg_z){
		x = arg_x;
		y = arg_y;
		z = arg_z;
	}

	Point(){
		x = y = z = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y,z+p.z); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y,z-p.z);}
	Point operator * (double a){ return Point(a*x,a*y,a*z); }
	Point operator / (double a){ return Point(x/a,y/a,z/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y + z*z; }

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS && fabs(z-p.z) < EPS;
	}
	double x,y,z;
};

struct Sphere{
	Point center;
	double r;
};

struct Circle{
	double x,y,r;
};

int N;
int boss[SIZE],height[SIZE];
Sphere info[SIZE];


int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	//既に同じグループなら何もしない
	if(boss_x == boss_y)return;

	//高さが高い方に吸収する
	if(height[x] > height[y]){

		boss[boss_y] = boss_x;

	}else if(height[x] < height[y]){

		boss[boss_x] = boss_y;

	}else{ //height[x] == height[y]

		boss[boss_y] = boss_x;
		height[x]++;
	}
}

void init(int num){

	for(int i = 0; i < num; i++){
		boss[i] = i;
		height[i] = 0;
	}
}

int calc_num_group(int num){

	int ret = 0;

	for(int i = 0; i < num; i++){

		if(i == get_boss(i)){

			ret++;
		}
	}
	return ret;
}

bool check(Sphere A,double H){


	return (A.center.z-A.r) < H && (A.center.z+A.r) > H;
}

void func(){

	vector<double> V;

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf %lf",&info[i].center.x,&info[i].center.y,&info[i].center.z,&info[i].r);

		V.push_back(info[i].center.z-info[i].r-ADD); //球の入場
		V.push_back(info[i].center.z-info[i].r+ADD);

		V.push_back(info[i].center.z+info[i].r-ADD); //球の退場
		V.push_back(info[i].center.z+info[i].r+ADD);
	}

	//球が結合する高さを調べる
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){
			if(info[i].center.z-info[i].r >= info[k].center.z+info[k].r ||
					info[i].center.z+info[i].r <= info[k].center.z-info[k].r)continue; //高さに重なりがないならSKIP

			double tmp_dist = sqrt((info[i].center.x-info[k].center.x)*(info[i].center.x-info[k].center.x)+
					(info[i].center.y-info[k].center.y)*(info[i].center.y-info[k].center.y));

			if(tmp_dist > info[i].r+info[k].r)continue; //同じ高さでも交差しないならSKIP

			double L = max(info[i].center.z-info[i].r,info[k].center.z-info[k].r);
			double R = min(info[i].center.z+info[i].r,info[k].center.z+info[k].r);
			double mid = (L+R)/2;

			double cross_H = BIG_NUM;

			for(int loop = 0; loop < 50 && fabs(R-L) > EPS; loop++){

				double i_H = mid-(info[i].center.z-info[i].r);
				double k_H = mid-(info[k].center.z-info[k].r);

				double i_R = sqrt(i_H*(2*info[i].r-i_H));
				double k_R = sqrt(k_H*(2*info[k].r-k_H));

				if(tmp_dist <= i_R+k_R){

					cross_H = mid;
					R = mid-EPS;

				}else{

					L = mid+EPS;
				}
				mid = (L+R)/2;
			}

			if(fabs(cross_H-BIG_NUM) < EPS)continue;

			V.push_back(cross_H-ADD);
			V.push_back(cross_H+ADD);

			//球が離れる時間を求める
			double leave_H = BIG_NUM;

			L = cross_H;
			R = min(info[i].center.z+info[i].r,info[k].center.z+info[k].r);
			mid = (L+R)/2;

			for(int loop = 0; loop < 50 && fabs(R-L) > EPS; loop++){

				double i_H = mid-(info[i].center.z-info[i].r);
				double k_H = mid-(info[k].center.z-info[k].r);

				double i_R = sqrt(i_H*(2*info[i].r-i_H));
				double k_R = sqrt(k_H*(2*info[k].r-k_H));

				if(tmp_dist > i_R+k_R){

					leave_H = mid;
					R = mid-EPS;

				}else{

					L = mid+EPS;
				}
				mid = (L+R)/2;
			}

			if(fabs(leave_H-cross_H) < EPS)continue; //内包していて離れない場合あり?

			V.push_back(leave_H-ADD);
			V.push_back(leave_H+ADD);
		}
	}

	sort(V.begin(),V.end());
	V.erase(unique(V.begin(),V.end()),V.end());

	vector<int> NUM;
	NUM.push_back(0);

	vector<Circle> CIRCLE;

	double pre_H = 0,H;

	for(int i = 0; i < V.size(); i++){

		if(fabs(V[i]-pre_H) < EPS)continue;

		H = V[i];

		CIRCLE.clear();

		//球を輪切りにして、円を作る
		for(int k = 0; k < N; k++){
			if(!check(info[k],H))continue;

			Circle circle;

			circle.x = info[k].center.x;
			circle.y = info[k].center.y;

			double tmp_h = H-(info[k].center.z-info[k].r); //球の一番下からの高さ
			circle.r = sqrt(tmp_h*(2*info[k].r-tmp_h));

			CIRCLE.push_back(circle);
		}

		if(CIRCLE.size() <= 1){

			NUM.push_back((int)CIRCLE.size());
			continue;
		}

		init((int)CIRCLE.size());

		for(int a = 0; a < CIRCLE.size()-1; a++){
			for(int b = a+1; b < CIRCLE.size(); b++){

				double tmp_dist = sqrt((CIRCLE[a].x-CIRCLE[b].x)*(CIRCLE[a].x-CIRCLE[b].x)+(CIRCLE[a].y-CIRCLE[b].y)*(CIRCLE[a].y-CIRCLE[b].y));

				if(tmp_dist < CIRCLE[a].r+CIRCLE[b].r){

					unite(a,b);
				}
			}
		}

		NUM.push_back(calc_num_group((int)CIRCLE.size()));
	}

	int num_change = 0;
	queue<int> ans;

	for(int i = 1; i < NUM.size(); i++){
		if(NUM[i] == NUM[i-1])continue;

		num_change++;
		if(NUM[i] > NUM[i-1]){

			ans.push(1);

		}else{

			ans.push(0);
		}
	}

	printf("%d\n",num_change);

	while(!ans.empty()){

		printf("%d",ans.front());
		ans.pop();
	}

	printf("\n");
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}



Measured memory_bytes: 3172