#include <iostream>
#include <vector>
#include <cmath>
#include <cstdio>

using namespace std;

template<class T>
ostream& operator<<(ostream& os, const vector<T>& vs) {
    if (vs.empty()) return os << "[]";
    os << "[" << vs[0];
    for (int i = 1; i < vs.size(); i++) os << " " << vs[i];
    return os << "]";
}

const double EPS = 1e-7;

struct Point {
    double x, y;
    Point(double x=0, double y=0) : x(x), y(y) {}
    Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
    Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
    Point operator*(double k) const { return Point(k * x, k * y); }
    Point operator/(double k) const { return Point(x / k, y / k); }
};
double dot(const Point& a, const Point& b) { return a.x * b.x + a.y * b.y; }
double cross(const Point& a, const Point& b) { return a.x * b.y - a.y * b.x; }
double norm(const Point& a) { return sqrt(dot(a, a)); }
Point rot90(const Point& p) { return Point(p.y, -p.x); } // 時計回りに90度回転 
ostream& operator<<(ostream& os, const Point& p) { return os << "(" << p.x << "," << p.y << ")"; }

struct Circle {
    Point p;
    double r;
    Circle(const Point& p=Point(0,0), double r=0) : p(p), r(r) {}
};
bool contains(const Circle& c, const Point& p) {
    return norm(c.p - p) < c.r + EPS;
}
bool contains(const Circle& a, const Circle& b) {
    return b.r + norm(a.p - b.p) < a.r + EPS;
}
bool intersects(const Circle& a, const Circle& b) {
    if (contains(a, b) || contains(b, a)) return false;
    return norm(a.p - b.p) < a.r + b.r + EPS;
}
ostream& operator<<(ostream& os, const Circle& c) {
    return os << "Circle[" << c.p << "," << c.r << "]";
}
vector<Point> crosspoint(const Circle& a, const Circle& b) {
    if (!intersects(a, b)) return vector<Point>();
    double d = norm(b.p - a.p);
    double x = (d * d + a.r * a.r - b.r * b.r) / (2 * d);
    double y = sqrt(a.r * a.r - x * x);
    Point v = b.p - a.p;
    vector<Point> ret(2);
    Point e = v / d;
    ret[0] = a.p + e * x + rot90(e) * y;
    ret[1] = a.p + e * x - rot90(e) * y;
    return ret;
}

int N;
vector<Point> ps;
vector<double> ls;
bool input() {
    cin >> N;
    if (N == 0) return false;
    ps.clear(); ps.resize(N);
    ls.clear(); ls.resize(N);
    for (int i = 0; i < N; i++) {
        cin >> ps[i].x >> ps[i].y >> ls[i];
    }
    return true;
}

bool C(double h) {
    vector<Circle> cs(N);
    for (int i = 0; i < N; i++) {
        cs[i].p = ps[i];
        cs[i].r = sqrt(ls[i] * ls[i] - h * h);
    }
    vector<Point> cands;
    for (int i = 0; i < N; i++) {
        cands.push_back(cs[i].p);
        for (int j = i + 1; j < N; j++) {
            const Circle& a = cs[i];
            const Circle& b = cs[j];
            if (contains(a, b) || contains(b, a)) continue;
            if (!intersects(a, b)) return false; // 共通部分を持たない2円が存在 
            vector<Point> xs = crosspoint(a, b);
            cands.insert(cands.end(), xs.begin(), xs.end());
        }
    }
    for (int i = 0; i < cands.size(); i++) {
        const Point& p = cands[i];
        for (int j = 0; j < N; j++) {
            if (!contains(cs[j], p)) {
                goto next;
            }
        }
        return true;
next:;
    }
    return false;
}

void solve() {
    double L = 0;
    for (int i = 0; i < N; i++) L = max(L, ls[i]);
    double lb = 1, ub = L;
    for (int i = 0; i < 300; i++) {
        double mid = (lb + ub) / 2;
        (C(mid) ? lb : ub) = mid;
    }
    printf("%.10lf\n", lb);
}

int main() {
    while (input()) solve();
    return 0;
}

Measured memory_bytes: 1272