#include <iostream>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
const double EPS = 1e-10;
const double INF = 1e12;
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
struct C{
    P p;
    double r;
    C(const P& p, const double& r) : p(p), r(r) {}
    C(){}
};

P unit(const P &p){
    return p/abs(p);
}
VP crosspointCC(C a, C b){
    VP ret;
    if(a.r < b.r) swap(a,b);
    double dist = abs(b.p-a.p);
    P dir = a.r*unit(b.p-a.p);
    if(EQ(dist, a.r+b.r) || EQ(dist, a.r-b.r)){
        ret.push_back(a.p +dir);
    }else if(a.r-b.r < dist && dist < a.r+b.r){
        double cos = (a.r*a.r +dist*dist -b.r*b.r)/(2*a.r*dist);
        double sin = sqrt(1 -cos*cos);
        ret.push_back(a.p +dir*P(cos, sin));
        ret.push_back(a.p +dir*P(cos, -sin));
    }
    return ret;
}

struct sphere{
    double x,y,z,r;
};
pair<double, double> cpzSS(const sphere &a, const sphere &b){
    double dx = b.x -a.x;
    double dy = b.y -a.y;
    double dz = b.z -a.z;
    double dxy = sqrt(dx*dx +dy*dy);
    C c1(P(0, 0), a.r), c2(P(dxy, dz), b.r);
    VP cp = crosspointCC(c1, c2);
    if(cp.empty()){
        return make_pair(0, 0);
    }
    return make_pair(cp[0].Y +a.z, cp[1].Y +a.z);
}

bool doubleeq(const double &a, const double &b){
    return abs(a-b) < EPS;
}

struct UnionFindTree{
    vector<int> v;
    int num;
    
    UnionFindTree(int n): v(n, -1), num(n){}
    int Find(int x){
        if(v[x] < 0) return x;
        return v[x] = Find(v[x]);
    }
    void Union(int a, int b){
        a = Find(a);
        b = Find(b);
        if(a == b) return;
        v[b] = a;
        num--;
    }
};

int main(){
    while(1){
        int n;
        cin >> n;
        if(n==0) break;

        vector<sphere> s(n);
        for(int i=0; i<n; i++){
            cin >> s[i].x >> s[i].y >> s[i].z >> s[i].r;
        }
        vector<double> cpz;
        cpz.push_back(0);
        cpz.push_back(1e5);
        for(int i=0; i<n; i++){
            cpz.push_back(s[i].z -s[i].r);
            cpz.push_back(s[i].z +s[i].r);
            for(int j=i+1; j<n; j++){
                pair<double, double> ret = cpzSS(s[i], s[j]);
                cpz.push_back(ret.first);
                cpz.push_back(ret.second);
            }
        }
        sort(cpz.begin(), cpz.end());
        cpz.erase(unique(cpz.begin(), cpz.end(), doubleeq), cpz.end());
        
        vector<int> numarea(cpz.size()-1);
        for(int i=0; i<(int)cpz.size()-1; i++){
            double z = (cpz[i] +cpz[i+1])/2;
            vector<C> c;
            for(int j=0; j<n; j++){
                double dz = abs(s[j].z -z);
                if(dz < s[j].r){
                    c.push_back(C(P(s[j].x, s[j].y), sqrt(s[j].r *s[j].r -dz *dz)));
                }
            }
            int m = c.size();
            UnionFindTree uft(m);
            for(int j=0; j<m; j++){
                for(int k=j+1; k<m; k++){
                    if(abs(c[j].p -c[k].p) < c[j].r +c[k].r){
                        uft.Union(j, k);
                    }
                }
            }
            numarea[i] = uft.num;
        }

        string ans="";
        for(int i=0; i<(int)numarea.size()-1; i++){
            if(numarea[i+1] -numarea[i] == 1){
                ans += "1";
            }
            if(numarea[i+1] -numarea[i] == -1){
                ans += "0";
            }
        }
        cout << ans.length() << endl;
        cout << ans << endl;
    }
    return 0;
}
