#include <bits/stdc++.h>

using namespace std;

#define REP(i, n) for (int i = 0; i < (n); i++)
#define ALL(x) x.begin(), x.end()
#define FOR(i, m, n) for (int i = (m); i < (n); i++)

using ll = long long;
typedef pair<int, int> pii;

//幾何 Geometry
const double PI = acos(-1);
const double EPS = 1e-10;
const bool DEBUG = false;

typedef complex<double> point;
istream &operator>>(istream &is, point &p) {
    double a, b;
    is >> a >> b;
    p = point(a, b);
    return is;
}
point operator*(const point &p, const double &d) { return point(real(p) * d, imag(p) * d); }
namespace std {
bool operator<(const point &a, const point &b) { return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b); }
}  // namespace std

//直線or線分
struct Line : public vector<point> {
    Line(const point &a, const point &b) {
        push_back(a);
        push_back(b);
    }
};
typedef vector<Line> Lines;

point direction(const point &p) {  //同じ向きの単位ベクトル
    return p / abs(p);
}
point orthogonal(const point &p) {  //法線ベクトル
    return point(-imag(p), real(p));
}
double cross(const point &a, const point &b) { return real(a) * imag(b) - imag(a) * real(b); }
double dot(const point &a, const point &b) { return real(a) * real(b) + imag(a) * imag(b); }
int ccw(point a, point b, point c) {
    b = b - a;
    c = c - a;
    if (cross(b, c) > EPS) return +1;   // counter clockwise
    if (cross(b, c) < -EPS) return -1;  // clockwise
    if (dot(b, c) < -EPS) return +2;    // c--a--b on line
    if (norm(b) < norm(c)) return -2;   // a--b--c on line
    return 0;
}
//交差判定
bool intersectLL(const Line &l1, const Line &l2) {
    return abs(cross(l1[1] - l1[0], l2[1] - l2[0])) > EPS ||  // non-parallel
           abs(cross(l1[1] - l1[0], l2[0] - l1[0])) < EPS;    // same line
}
bool intersectLS(const Line &l, const Line &s) {
    return cross(l[1] - l[0], s[0] - l[0]) *  // s[0] is left of l
               cross(l[1] - l[0], s[1] - l[0]) <
           EPS;  // s[1] is right of l
}
bool intersectLP(const Line &l, const point &p) { return abs(cross(l[1] - p, l[0] - p)) < EPS; }
//端点に乗ってたらfalse
bool intersectSP_without_endpoint(const Line &s, const point &p) {
    if (abs(s[0] - p) < EPS || abs(s[1] - p) < EPS) return false;
    return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS;  // triangle inequality
}

bool intersectSP(const Line &s, const point &p) {
    // verified on 2020/04/03
    // https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
    return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS;  // triangle inequality
}
bool isOnSegment(const Line &s, const Line &t) {
    if (intersectSP(s, t[0]) || intersectSP(s, t[1]) || intersectSP(t, s[0]) || intersectSP(t, s[1]))
        return true;
    else
        return false;
}
bool isSamePoint(const point &p1, const point &p2) { return abs(p1 - p2) < EPS; }
bool connectSS(const Line &s, const Line &t) {
    REP(i, 2) REP(j, 2) {
        if (s[i] == t[j]) return true;
    }
    return false;
}
bool intersectSS(const Line &s, const Line &t) {
    return ccw(s[0], s[1], t[0]) * ccw(s[0], s[1], t[1]) <= 0 && ccw(t[0], t[1], s[0]) * ccw(t[0], t[1], s[1]) <= 0;
}
//端点が線分上に乗っている場合はfalseにする
bool intersectSS_strict(const Line &s, const Line &t) {
    if (isOnSegment(s, t)) return false;
    return ccw(s[0], s[1], t[0]) * ccw(s[0], s[1], t[1]) <= 0 && ccw(t[0], t[1], s[0]) * ccw(t[0], t[1], s[1]) <= 0;
}

//距離,交点
//射影 直線lにpから下した垂線との交点
point projection(
    const Line &l,
    const point &p) {  // verified on 2020/04/03
                       // https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
    double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
    return l[0] + (l[0] - l[1]) * t;
}
//射影 直線lを対象軸としてpと線対称にある点
point reflection(const Line &l, const point &p) { return p + (projection(l, p) - p) * 2; }
double distancePP(const point &a, const point &b) { return sqrt(norm(a - b)); }
double distanceLP(const Line &l, const point &p) { return abs(p - projection(l, p)); }
double distanceLL(const Line &l, const Line &m) { return intersectLL(l, m) ? 0 : distanceLP(l, m[0]); }
double distanceLS(const Line &l, const Line &s) {
    if (intersectLS(l, s)) return 0;
    return min(distanceLP(l, s[0]), distanceLP(l, s[1]));
}
double distanceSP(const Line &s, const point &p) {
    const point r = projection(s, p);
    if (intersectSP(s, r)) return abs(r - p);
    return min(abs(s[0] - p), abs(s[1] - p));
}
double distanceSS(const Line &s, const Line &t) {
    // verified on 2020/04/03
    // https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
    if (intersectSS(s, t)) return 0;
    return min({distanceSP(s, t[0]), distanceSP(s, t[1]), distanceSP(t, s[0]), distanceSP(t, s[1])});
}
point crosspoint(const Line &l, const Line &m) {
    double A = cross(l[1] - l[0], m[1] - m[0]);
    double B = cross(l[1] - l[0], l[1] - m[0]);
    if (abs(A) < EPS && abs(B) < EPS) return m[0];  // same line
    if (abs(A) < EPS) assert(false);                // Precondition not satisfied
    return m[0] + B / A * (m[1] - m[0]);
}
double dist(point &p1, point &p2) { return abs(p1 - p2); }

struct rope {
    point p;
    double l;
    rope(point p_, double l_) : p(p_), l(l_) {}
};
struct point3d {
    point p;
    double z;
    point3d(point p_, double z_) : p(p_), z(z_) {}
};

point3d two_ropes(int i, int j, vector<rope> &ropes, int N) {
    if (ropes[i].l > ropes[j].l) swap(i, j);
    point p = ropes[i].p, q = ropes[j].p;
    point v = q - p;
    double t = (pow(ropes[i].l, 2) - pow(ropes[j].l, 2) + pow(abs(v), 2)) / (2 * abs(v));
    point m = p + direction(v) * t;
    double h = sqrt(pow(ropes[i].l, 2) - pow(abs(m - p), 2));
    bool ok = true;
    // cout << ropes[i].p << ropes[j].p << m << h << endl;

    if (ropes[j].l > ropes[i].l + dist(p, q) + EPS) ok = false;
    if (ok) {
        point3d ret(m, h);
        return ret;
    } else {
        point3d ret(0, -1);
        return ret;
    }
}

void solve() {
    int N;
    cin >> N;
    if (N == 0) exit(0);
    vector<rope> ropes;
    REP(i, N) {
        double x, y, l;
        cin >> x >> y >> l;
        point p(x, y);
        rope r(p, l);
        ropes.push_back(r);
    }
    double ans = 0;

    // 1本が張る
    REP(i, N) {
        point p = ropes[i].p;
        double h = ropes[i].l;
        bool ok = true;
        REP(j, N) {
            if (i == j) continue;
            if (pow(dist(ropes[j].p, p), 2) + pow(h, 2) > pow(ropes[j].l, 2) + EPS) ok = false;
        }
        if (ok) ans = max(ans, h);
    }

    // 2本が張る
    REP(i, N) {
        FOR(j, i + 1, N) {
            point3d po = two_ropes(i, j, ropes, N);

            point m = po.p;
            // cout << ropes[i].p << ropes[j].p << m << po.z << endl;
            double h = po.z;
            bool ok = true;
            REP(k, N) {
                // if (k == i || k == j) continue;
                double d = sqrt(pow(dist(ropes[k].p, m), 2) + pow(h, 2));
                if (ropes[k].l + EPS < d) ok = false;
            }
            if (ok) ans = max(ans, h);
        }
    }

    // 3本が張る
    REP(i, N) {
        FOR(j, i + 1, N) {
            point3d po = two_ropes(i, j, ropes, N);
            point p = ropes[i].p, q = ropes[j].p, m = po.p;
            if (po.z < 0) continue;
            //
            REP(k, N) {
                if (k == i || k == j) continue;

                {
                    double ok = 0, ng = PI / 2;
                    double L = po.z;
                    REP(_, 50) {
                        double mid = (ok + ng) / 2;
                        double z = L * sin(mid);
                        point v = direction(m - p);
                        //時計回りに90度回転
                        point v2 = v * point(0, -1);
                        point M = m + v2 * L * cos(mid);
                        double d = sqrt(pow(abs(M - ropes[k].p), 2) + pow(z, 2));
                        if (d <= ropes[k].l + EPS)
                            ok = mid;
                        else
                            ng = mid;
                        //
                    }
                    double mid = ok;
                    double z = L * sin(mid);
                    point v = direction(m - p);
                    //時計回りに90度回転
                    point v2 = v * point(0, -1);
                    point M = m + v2 * L * cos(mid);
                    bool possible = true;
                    REP(idx, N) {
                        // if (idx == i || idx == j || idx == k) continue;
                        double d = sqrt(pow(abs(M - ropes[idx].p), 2) + z * z);
                        if (d > ropes[idx].l + EPS) possible = false;
                    }
                    if (possible) ans = max(ans, z);
                }
                {
                    double ok = 0, ng = PI / 2;
                    double L = po.z;
                    REP(_, 50) {
                        double mid = (ok + ng) / 2;
                        double z = L * sin(mid);
                        point v = direction(m - p);
                        //反時計回りに90度回転
                        point v2 = v * point(0, 1);
                        point M = m + v2 * L * cos(mid);
                        double d = sqrt(pow(abs(M - ropes[k].p), 2) + pow(z, 2));
                        if (d <= ropes[k].l + EPS)
                            ok = mid;
                        else
                            ng = mid;
                        //
                    }
                    double mid = ok;
                    double z = L * sin(mid);
                    point v = direction(m - p);
                    //反時計回りに90度回転
                    point v2 = v * point(0, 1);
                    point M = m + v2 * L * cos(mid);
                    bool possible = true;
                    REP(idx, N) {
                        // if (idx == i || idx == j || idx == k) continue;
                        double d = sqrt(pow(abs(M - ropes[idx].p), 2) + z * z);
                        if (d > ropes[idx].l + EPS) possible = false;
                    }
                    if (possible) ans = max(ans, z);
                }
            }
        }
    }
    cout << fixed << setprecision(6) << ans << endl;
}

signed main() {
    while (true) solve();
}


Measured memory_bytes: 3596