#include<bits/stdc++.h>
using namespace std;
const int maxn = 2005+5;
struct node{
double l, r, h;
int type;
node(){};
node(double l, double r, double h, int type):l(l),r(r), h(h), type(type){};
bool operator<(const node x)const{
return h < x.h;
}
}cc[maxn<<2];
struct tree{
int l, r, cnt, lazy;
double len;
int mid(){return (l+r)/2;}
}tr[maxn<<2];
vector<double>ve;
int getid(double x) {
return lower_bound(ve.begin(), ve.end(), x)-ve.begin()+1;
}
void build(int rt, int l, int r) {
tr[rt].l = l; tr[rt].r = r;tr[rt].cnt = tr[rt].len = 0;
if(l == r) return;
int mid = tr[rt].mid();
build(rt<<1, l, mid);
build(rt<<1|1, mid+1, r);
}
void pushdown(int rt) {
if(tr[rt].cnt) tr[rt].len = ve[tr[rt].r]-ve[tr[rt].l-1];
else if(tr[rt].l == tr[rt].r) tr[rt].len = 0;
else tr[rt].len = tr[rt<<1].len + tr[rt<<1|1].len;
}
void update(int rt, int l, int r, int type) {
if(tr[rt].l == l && tr[rt].r == r) {
tr[rt].cnt += type;
pushdown(rt);
return;
}
int mid = tr[rt].mid();
if(r <= mid) update(rt<<1, l, r, type);
else if(l > mid) update(rt<<1|1, l, r, type);
else{
update(rt<<1, l, mid, type);
update(rt<<1|1, mid+1, r, type);
}
pushdown(rt);
}
int main() {
int T = 0, n;
while(scanf("%d", &n) == 1 && n) {
int pos = 0;
ve.clear();
for(int i = 1; i <= n; i++) {
double x1, x2, y1, y2;
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
ve.push_back(x1);ve.push_back(x2);
cc[++pos] = node(x1, x2, y1, 1);
cc[++pos] = node(x1, x2, y2, -1);
}
sort(cc+1, cc+1+pos);
sort(ve.begin(), ve.end());
ve.erase(unique(ve.begin(), ve.end()), ve.end());
double res = 0;
build(1, 1, ve.size());
for(int i = 1; i < pos; i++) {
int l = getid(cc[i].l);
int r = getid(cc[i].r)-1;
update(1, l, r, cc[i].type);
res += tr[1].len*(cc[i+1].h-cc[i].h);
}
printf("Test case #%d\nTotal explored area: %.2lf\n\n", ++T, res);
}
return 0;
}